diff options
149 files changed, 3326 insertions, 2193 deletions
diff --git a/.builds/alpine.yml b/.builds/alpine.yml index dc5e7c11..7f0bef02 100644 --- a/.builds/alpine.yml +++ b/.builds/alpine.yml | |||
@@ -6,6 +6,7 @@ packages: | |||
6 | - json-c-dev | 6 | - json-c-dev |
7 | - libevdev-dev | 7 | - libevdev-dev |
8 | - libinput-dev | 8 | - libinput-dev |
9 | - libseat-dev | ||
9 | - libxcb-dev | 10 | - libxcb-dev |
10 | - libxkbcommon-dev | 11 | - libxkbcommon-dev |
11 | - mesa-dev | 12 | - mesa-dev |
@@ -16,7 +17,8 @@ packages: | |||
16 | - wayland-dev | 17 | - wayland-dev |
17 | - wayland-protocols | 18 | - wayland-protocols |
18 | - xcb-util-image-dev | 19 | - xcb-util-image-dev |
19 | - xorg-server-xwayland | 20 | - xcb-util-wm-dev |
21 | - xwayland | ||
20 | sources: | 22 | sources: |
21 | - https://github.com/swaywm/sway | 23 | - https://github.com/swaywm/sway |
22 | - https://github.com/swaywm/wlroots | 24 | - https://github.com/swaywm/wlroots |
@@ -28,7 +30,7 @@ tasks: | |||
28 | sudo ninja -C build install | 30 | sudo ninja -C build install |
29 | - setup: | | 31 | - setup: | |
30 | cd sway | 32 | cd sway |
31 | meson build -Dauto_features=enabled -Dtray=disabled | 33 | meson build --fatal-meson-warnings -Dauto_features=enabled -Dtray=disabled |
32 | - build: | | 34 | - build: | |
33 | cd sway | 35 | cd sway |
34 | ninja -C build | 36 | ninja -C build |
@@ -36,3 +38,10 @@ tasks: | |||
36 | cd sway | 38 | cd sway |
37 | meson configure build -Dxwayland=disabled | 39 | meson configure build -Dxwayland=disabled |
38 | ninja -C build | 40 | ninja -C build |
41 | - build-static: | | ||
42 | cd sway | ||
43 | mkdir subprojects | ||
44 | ln -s ../../wlroots subprojects/wlroots | ||
45 | rm -rf build | ||
46 | meson build --fatal-meson-warnings --default-library=static --force-fallback-for=wlroots | ||
47 | ninja -C build | ||
diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml index c0f70186..a8f1dfed 100644 --- a/.builds/archlinux.yml +++ b/.builds/archlinux.yml | |||
@@ -13,7 +13,9 @@ packages: | |||
13 | - wayland | 13 | - wayland |
14 | - wayland-protocols | 14 | - wayland-protocols |
15 | - xcb-util-image | 15 | - xcb-util-image |
16 | - xcb-util-wm | ||
16 | - xorg-xwayland | 17 | - xorg-xwayland |
18 | - seatd | ||
17 | sources: | 19 | sources: |
18 | - https://github.com/swaywm/sway | 20 | - https://github.com/swaywm/sway |
19 | - https://github.com/swaywm/wlroots | 21 | - https://github.com/swaywm/wlroots |
@@ -25,7 +27,7 @@ tasks: | |||
25 | sudo ninja -C build install | 27 | sudo ninja -C build install |
26 | - setup: | | 28 | - setup: | |
27 | cd sway | 29 | cd sway |
28 | meson build -Dauto_features=enabled -Dsd-bus-provider=libsystemd | 30 | meson build --fatal-meson-warnings -Dauto_features=enabled -Dsd-bus-provider=libsystemd |
29 | - build: | | 31 | - build: | |
30 | cd sway | 32 | cd sway |
31 | ninja -C build | 33 | ninja -C build |
diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 273badbc..1a3c8512 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml | |||
@@ -19,6 +19,7 @@ packages: | |||
19 | - devel/libudev-devd | 19 | - devel/libudev-devd |
20 | - graphics/libdrm | 20 | - graphics/libdrm |
21 | - graphics/mesa-libs | 21 | - graphics/mesa-libs |
22 | - sysutils/seatd | ||
22 | - x11/libinput | 23 | - x11/libinput |
23 | - x11/libX11 | 24 | - x11/libX11 |
24 | - x11/pixman | 25 | - x11/pixman |
@@ -33,7 +34,7 @@ tasks: | |||
33 | cd subprojects | 34 | cd subprojects |
34 | ln -s ../../wlroots wlroots | 35 | ln -s ../../wlroots wlroots |
35 | cd .. | 36 | cd .. |
36 | meson build -Dtray=enabled -Dsd-bus-provider=basu | 37 | meson build --fatal-meson-warnings -Dtray=enabled -Dsd-bus-provider=basu |
37 | - build: | | 38 | - build: | |
38 | cd sway | 39 | cd sway |
39 | ninja -C build | 40 | ninja -C build |
diff --git a/.clang-format b/.clang-format index 5818da3c..24ea869d 100644 --- a/.clang-format +++ b/.clang-format | |||
@@ -8,9 +8,11 @@ IndentCaseLabels: false | |||
8 | SortIncludes: false | 8 | SortIncludes: false |
9 | ColumnLimit: 80 | 9 | ColumnLimit: 80 |
10 | AlignAfterOpenBracket: DontAlign | 10 | AlignAfterOpenBracket: DontAlign |
11 | BinPackParameters: false | 11 | BinPackParameters: true |
12 | BinPackArguments: false | 12 | BinPackArguments: true |
13 | ContinuationIndentWidth: 8 | 13 | ContinuationIndentWidth: 8 |
14 | AllowAllParametersOfDeclarationOnNextLine: false | 14 | AllowAllParametersOfDeclarationOnNextLine: false |
15 | AllowShortLoopsOnASingleLine: true | 15 | AllowShortLoopsOnASingleLine: true |
16 | ReflowComments: false | 16 | ReflowComments: false |
17 | AllowAllArgumentsOnNextLine: false | ||
18 | AlignOperands: DontAlign | ||
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index 156accde..8542b7b9 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md | |||
@@ -6,10 +6,9 @@ labels: 'bug' | |||
6 | --- | 6 | --- |
7 | 7 | ||
8 | ### Please read the following before submitting: | 8 | ### Please read the following before submitting: |
9 | - Please do NOT submit bug reports for questions. Ask questions on IRC at #sway on irc.freenode.net. | 9 | - Please do NOT submit bug reports for questions. Ask questions on IRC at #sway on Libera Chat. |
10 | - Proprietary graphics drivers, including nvidia, are not supported. Please use the open source equivalents, such as nouveau, if you would like to use Sway. | 10 | - Proprietary graphics drivers, including nvidia, are not supported. Please use the open source equivalents, such as nouveau, if you would like to use Sway. |
11 | - 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. | 11 | - 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. |
12 | - 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 osbolete workarounds. | ||
13 | If you fix a script or find outdated information, don't hesitate to adjust the wiki page. | 12 | If you fix a script or find outdated information, don't hesitate to adjust the wiki page. |
14 | 13 | ||
15 | ### Please fill out the following: | 14 | ### Please fill out the following: |
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index f09cdf5b..0092609b 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml | |||
@@ -1,5 +1,5 @@ | |||
1 | blank_issues_enabled: false | 1 | blank_issues_enabled: false |
2 | contact_links: | 2 | contact_links: |
3 | - name: Questions | 3 | - name: Questions |
4 | url: "http://webchat.freenode.net/?channels=sway&uio=d4" | 4 | url: "https://libera.chat" |
5 | about: "Please ask questions on IRC in #sway on irc.freenode.net" | 5 | about: "Please ask questions on IRC in #sway on Libera Chat" |
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c17afdda..4f043f7a 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md | |||
@@ -1,9 +1,8 @@ | |||
1 | # Contributing to sway | 1 | # Contributing to sway |
2 | 2 | ||
3 | Contributing just involves sending a pull request. You will probably be more | 3 | Contributing just involves sending a pull request. You will probably be more |
4 | successful with your contribution if you visit | 4 | successful with your contribution if you visit #sway-devel on Libera Chat |
5 | [#sway-devel](https://webchat.freenode.net/?channels=sway-devel) on | 5 | upfront and discuss your plans. |
6 | irc.freenode.net upfront and discuss your plans. | ||
7 | 6 | ||
8 | Note: rules are made to be broken. Adjust or ignore any/all of these as you see | 7 | Note: rules are made to be broken. Adjust or ignore any/all of these as you see |
9 | fit, but be prepared to justify it to your peers. | 8 | fit, but be prepared to justify it to your peers. |
diff --git a/README.de.md b/README.de.md index 24e66a60..6e1e8ca9 100644 --- a/README.de.md +++ b/README.de.md | |||
@@ -1,8 +1,8 @@ | |||
1 | # Sway | 1 | # Sway |
2 | 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). | 2 | 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). |
3 | 3 | ||
4 | ## Signaturen | 4 | ## Signaturen |
5 | 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. | 5 | Jedes Release wird mit dem PGP-Schlüssel [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48) signiert und auf GitHub veröffentlicht. |
6 | 6 | ||
7 | ## Installation | 7 | ## Installation |
8 | ### Mit der Paketverwaltung | 8 | ### Mit der Paketverwaltung |
diff --git a/README.dk.md b/README.dk.md index 535000c3..94c0b9eb 100644 --- a/README.dk.md +++ b/README.dk.md | |||
@@ -1,41 +1,43 @@ | |||
1 | # Sway | 1 | # Sway |
2 | 2 | ||
3 | Sway er en [i3](https://i3wm.org/)-kompatibel [Wayland](http://wayland.freedesktop.org/) compositor. | 3 | Sway er en [i3]-kompatibel [Wayland] compositor. Læs [Ofte stillede spørgsmål]. |
4 | Læs [Ofte stillede spørgsmål](https://github.com/swaywm/sway/wiki). | 4 | Deltag på [IRC kanalen][IRC kanal] \(#sway på irc.libera.chat). |
5 | Deltag på [IRC kanalen](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway på irc.freenode.net). | ||
6 | 5 | ||
7 | ## Udgivelses Signaturer | 6 | ## Udgivelses Signaturer |
8 | 7 | ||
9 | Udgivelser er signeret med [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) | 8 | Udgivelser er signeret med [E88F5E48] og publiceret [på GitHub][GitHub |
10 | og publiseret på [GitHub](https://github.com/swaywm/sway/releases). | 9 | releases]. |
11 | 10 | ||
12 | ## Installation | 11 | ## Installation |
13 | 12 | ||
14 | ### Fra Pakker | 13 | ### Fra pakker |
15 | 14 | ||
16 | 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) | 15 | Sway er tilgængelig i mange distributioner. Prøv at installere "sway" pakken |
17 | for information om installation til din(e) distribution(er). | 16 | fra din. |
18 | 17 | ||
19 | Hvis du er interesseret i at lave en Sway pakke til din distribution, burde du besøge IRC | 18 | Hvis du er interesseret i at pakke Sway til din distribution, kan du tage forbi |
20 | kanalen eller sende en e-mail til sir@cmpwn.com for rådgivning. | 19 | IRC kanalen eller sende en email til sir@cmpwn.com for rådgivning. |
21 | 20 | ||
22 | ### Kompilering fra kildekode | 21 | ### Kompilering fra kildekode |
23 | 22 | ||
24 | Installation afhænger af følgende programmer: | 23 | Se [denne wiki-side][Opsætning til udvikling] hvis du vil bygge HEAD af sway og |
24 | wlroots til test eller udvikling. | ||
25 | |||
26 | Installationsafhængigheder: | ||
25 | 27 | ||
26 | * meson \* | 28 | * meson \* |
27 | * [wlroots](https://github.com/swaywm/wlroots) | 29 | * [wlroots] |
28 | * wayland | 30 | * wayland |
29 | * wayland-protocols \* | 31 | * wayland-protocols \* |
30 | * pcre | 32 | * pcre |
31 | * json-c | 33 | * json-c |
32 | * pango | 34 | * pango |
33 | * cairo | 35 | * cairo |
34 | * gdk-pixbuf2 (valgfrit tillæg: system tray) | 36 | * gdk-pixbuf2 (valgfrit: system tray) |
35 | * [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (valgfrit tillæg: man pages) \* | 37 | * [scdoc] (valgfrit: man pages) \* |
36 | * git \* | 38 | * git \* |
37 | 39 | ||
38 | _\*Kompiler krav_ | 40 | _\*Kompileringsafhængighed_ |
39 | 41 | ||
40 | Kør følgende kommandoer: | 42 | Kør følgende kommandoer: |
41 | 43 | ||
@@ -43,21 +45,30 @@ Kør følgende kommandoer: | |||
43 | ninja -C build | 45 | ninja -C build |
44 | sudo ninja -C build install | 46 | sudo ninja -C build install |
45 | 47 | ||
46 | På systemer uden 'logind', behøver du at sætte ejerens bruger-id for Sways eksekverbare filer - såkaldt SUID (Set owner User ID): | 48 | På systemer uden logind eller seatd skal du sætte SUID bit på sway filen: |
47 | 49 | ||
48 | sudo chmod a+s /usr/local/bin/sway | 50 | sudo chmod a+s /usr/local/bin/sway |
49 | 51 | ||
50 | Sway vil frasige sig 'root' tilladelser kort efter opstart | 52 | Sway dropper 'root' tilladelser kort efter opstart. |
51 | 53 | ||
52 | ## Konfiguration | 54 | ## Konfiguration |
53 | 55 | ||
54 | Hvis du allerede bruger i3, bør du kopiere din i3-konfiguration til `~/.config/sway/config` og | 56 | Hvis du allerede bruger i3 kan du bare kopiere din i3 konfiguration til |
55 | det vil bare fungerer. Ellers skal du kopiere eksempel konfigurations filen til | 57 | `~/.config/sway/config`. Ellers skal du kopiere eksempelkonfigurationsfilen til |
56 | `~/.config/sway/config`. Den er normalt placeret i `/etc/sway/config`. | 58 | `~/.config/sway/config`. Den er normalt placeret i `/etc/sway/config`. Kør |
57 | Kør `man 5 sway` for at få oplysninger om konfigurationen. | 59 | `man 5 sway` for at få oplysninger om konfigurationen. |
58 | 60 | ||
59 | ## Kører | 61 | ## Eksekvering |
60 | 62 | ||
61 | Kør `sway` fra en TTY. Nogle display managers fungerer muligvis, men understøttes ikke af | 63 | Kør `sway` fra en TTY. Nogle display managers kan fungere, men Sway yder ikke |
62 | Sway (gdm er kendt for at fungere temmelig godt). | 64 | support til dem (gdm er kendt for at fungere temmelig godt). |
63 | 65 | ||
66 | [i3]: https://i3wm.org/ | ||
67 | [Wayland]: http://wayland.freedesktop.org/ | ||
68 | [Ofte stillede spørgsmål]: https://github.com/swaywm/sway/wiki | ||
69 | [IRC kanal]: https://web.libera.chat/gamja/?channels=#sway | ||
70 | [E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48 | ||
71 | [GitHub releases]: https://github.com/swaywm/sway/releases | ||
72 | [Opsætning til udvikling]: https://github.com/swaywm/sway/wiki/Development-Setup | ||
73 | [wlroots]: https://github.com/swaywm/wlroots | ||
74 | [scdoc]: https://git.sr.ht/~sircmpwn/scdoc | ||
diff --git a/README.es.md b/README.es.md index 53f11f68..951a2eba 100644 --- a/README.es.md +++ b/README.es.md | |||
@@ -1,12 +1,12 @@ | |||
1 | # sway | 1 | # sway |
2 | 2 | ||
3 | sway es un compositor de [Wayland](http://wayland.freedesktop.org/) compatible con [i3](https://i3wm.org/). | 3 | sway es un compositor de [Wayland](http://wayland.freedesktop.org/) compatible con [i3](https://i3wm.org/). |
4 | Lea el [FAQ](https://github.com/swaywm/sway/wiki). Únase al [canal de IRC](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on | 4 | Lea el [FAQ](https://github.com/swaywm/sway/wiki). Únase al [canal de IRC](https://web.libera.chat/gamja/?channels=#sway) (#sway on |
5 | irc.freenode.net). | 5 | irc.libera.chat). |
6 | 6 | ||
7 | ## Firmas de las versiones | 7 | ## Firmas de las versiones |
8 | 8 | ||
9 | Las distintas versiones están firmadas con [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) | 9 | Las distintas versiones están firmadas con [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48) |
10 | y publicadas [en GitHub](https://github.com/swaywm/sway/releases). | 10 | y publicadas [en GitHub](https://github.com/swaywm/sway/releases). |
11 | 11 | ||
12 | ## Instalación | 12 | ## Instalación |
diff --git a/README.fr.md b/README.fr.md index a72696d6..d1f4f934 100644 --- a/README.fr.md +++ b/README.fr.md | |||
@@ -1,48 +1,49 @@ | |||
1 | # sway | 1 | # sway |
2 | 2 | ||
3 | Sway est un compositeur [Wayland](http://wayland.freedesktop.org/) compatible | 3 | Sway est un compositeur [Wayland] compatible avec [i3]. Lisez la |
4 | avec [i3](https://i3wm.org/), **en cours de développement**. Lisez la | 4 | [FAQ]. Rejoignez le [canal IRC] (#sway sur irc.libera.chat). |
5 | [FAQ](https://github.com/swaywm/sway/wiki). Rejoignez le [canal | ||
6 | IRC](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway sur | ||
7 | irc.freenode.net). | ||
8 | 5 | ||
9 | ## Aide en français | 6 | ## Aide en français |
10 | 7 | ||
11 | [abdelq](//github.com/abdelq) fournit du support en français sur IRC et Github, dans le fuseau horaire UTC-4 (EST). | 8 | [abdelq] fournit du support en français sur IRC et Github, dans le fuseau |
9 | horaire UTC-4 (EST). | ||
12 | 10 | ||
13 | ## Signatures de nouvelles versions | 11 | ## Signatures de nouvelles versions |
14 | 12 | ||
15 | Les nouvelles versions sont signées avec [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) | 13 | Les nouvelles versions sont signées avec [E88F5E48] et publiées |
16 | et publiées [sur GitHub](https://github.com/swaywm/sway/releases). | 14 | [sur GitHub][versions GitHub]. |
17 | 15 | ||
18 | ## Installation | 16 | ## Installation |
19 | 17 | ||
20 | ### À partir de paquets | 18 | ### À partir de paquets |
21 | 19 | ||
22 | Sway est disponible sur plusieurs distributions. Essayez d'installer le paquet "sway" pour | 20 | Sway est disponible sur beaucoup de distributions. Essayez d'installer le |
23 | la vôtre. Si ce n'est pas disponible, consultez [cette page wiki](https://github.com/swaywm/sway/wiki/Unsupported-packages) | 21 | paquet "sway" pour la vôtre. |
24 | pour de l'information sur l'installation pour vos distributions. | ||
25 | 22 | ||
26 | Si vous êtes intéressé à maintenir Sway pour votre distribution, passez par le canal | 23 | Si vous êtes intéressé à maintenir Sway pour votre distribution, passez sur le |
27 | IRC ou envoyez un e-mail à sir@cmpwn.com (en anglais seulement) pour des conseils. | 24 | canal IRC ou envoyez un e-mail à sir@cmpwn.com (en anglais seulement) pour des |
25 | conseils. | ||
28 | 26 | ||
29 | ### Compilation depuis la source | 27 | ### Compilation depuis les sources |
28 | |||
29 | Consultez [cette page wiki][Configuration de développement] si vous souhaitez | ||
30 | compiler la révision HEAD de sway et wlroots pour tester ou développer. | ||
30 | 31 | ||
31 | Installez les dépendances : | 32 | Installez les dépendances : |
32 | 33 | ||
33 | * meson \* | 34 | * meson \* |
34 | * [wlroots](https://github.com/swaywm/wlroots) | 35 | * [wlroots] |
35 | * wayland | 36 | * wayland |
36 | * wayland-protocols \* | 37 | * wayland-protocols \* |
37 | * pcre | 38 | * pcre |
38 | * json-c | 39 | * json-c |
39 | * pango | 40 | * pango |
40 | * cairo | 41 | * cairo |
41 | * gdk-pixbuf2 (optionnel: system tray) | 42 | * gdk-pixbuf2 (optionnel : system tray) |
42 | * [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (optionnel: requis pour les pages man) \* | 43 | * [scdoc] (optionnel : requis pour les pages man) \* |
43 | * git \* | 44 | * git (optionnel : information de version) \* |
44 | 45 | ||
45 | _\*Requis uniquement pour la compilation_ | 46 | _\* Requis uniquement pour la compilation_ |
46 | 47 | ||
47 | Exécutez ces commandes : | 48 | Exécutez ces commandes : |
48 | 49 | ||
@@ -58,12 +59,25 @@ Sway se débarassera des permissions *root* peu de temps après le démarrage. | |||
58 | 59 | ||
59 | ## Configuration | 60 | ## Configuration |
60 | 61 | ||
61 | Si vous utilisez déjà i3, copiez votre configuration i3 à `~/.config/sway/config` et | 62 | Si vous utilisez déjà i3, copiez votre configuration i3 vers |
62 | cela va fonctionner. Sinon, copiez l'exemple de fichier de configuration à | 63 | `~/.config/sway/config` et sway fonctionnera directement. Sinon, copiez |
63 | `~/.config/sway/config`. Il se trouve généralement dans `/etc/sway/config`. | 64 | l'exemple de fichier de configuration vers `~/.config/sway/config`. Il se |
64 | Exécutez `man 5 sway` pour l'information sur la configuration. | 65 | trouve généralement dans `/etc/sway/config`. Exécutez `man 5 sway` pour lire la |
66 | documentation pour la configuration de sway. | ||
65 | 67 | ||
66 | ## Exécution | 68 | ## Exécution |
67 | 69 | ||
68 | Exécutez `sway` à partir d'un TTY. Certains gestionnaires d'affichage peuvent fonctionner, | 70 | Exécutez `sway` à partir d'un TTY. Certains gestionnaires d'affichage peuvent |
69 | mais ne sont pas supportés par Sway (gdm est réputé pour assez bien fonctionner). | 71 | fonctionner, mais ne sont pas supportés par Sway (gdm est réputé pour assez |
72 | bien fonctionner). | ||
73 | |||
74 | [Wayland]: http://wayland.freedesktop.org/ | ||
75 | [i3]: https://i3wm.org/ | ||
76 | [FAQ]: https://github.com/swaywm/sway/wiki | ||
77 | [canal IRC]: https://web.libera.chat/gamja/?channels=#sway | ||
78 | [abdelq]: https://github.com/abdelq | ||
79 | [E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48 | ||
80 | [versions GitHub]: https://github.com/swaywm/sway/releases | ||
81 | [Configuration de développement]: https://github.com/swaywm/sway/wiki/Development-Setup | ||
82 | [wlroots]: https://github.com/swaywm/wlroots | ||
83 | [scdoc]: https://git.sr.ht/~sircmpwn/scdoc | ||
diff --git a/README.gr.md b/README.gr.md new file mode 100644 index 00000000..5bb04932 --- /dev/null +++ b/README.gr.md | |||
@@ -0,0 +1,73 @@ | |||
1 | # Sway | ||
2 | |||
3 | Το sway Îνα [i3]-συμβατό [Wayland] compositor. Διαβάστε το [FAQ]. Μπείτε στο | ||
4 | [IRC channel] \(#sway on irc.libera.chat). | ||
5 | |||
6 | ## ΥπογÏαφÎÏ‚ δημοσιεÏσεων | ||
7 | |||
8 | Οι εκδόσεις είναι υπογεÏαμμÎνες με [E88F5E48] και δημοσιευμÎνες [στο GitHub][GitHub releases]. | ||
9 | |||
10 | ## Εγκατάσταση | ||
11 | |||
12 | ### Από πακÎτα | ||
13 | |||
14 | Το Sway είναι διαθÎσιμο σε πολλά distributions. Δοκιμάστε εγκαταστώντας το "sway" package για | ||
15 | το δικό σας. | ||
16 | |||
17 | Εάν ενδιαφÎÏεστε για packaging του sway για το distribution σας, να πάτε στο IRC | ||
18 | channel ή στείλτε Îνα email στο sir@cmpwn.com για συμβουλÎÏ‚. | ||
19 | |||
20 | ### Compiling από πηγή | ||
21 | |||
22 | ΤσεκάÏετε [αυτό το wiki page][Development setup] εάμα θÎλετε να κάνετε build το HEAD του | ||
23 | sway και wlroots γιά τεστάÏισμα ή development. | ||
24 | |||
25 | Εγκατάσταση των dependencies: | ||
26 | |||
27 | * meson \* | ||
28 | * [wlroots] | ||
29 | * wayland | ||
30 | * wayland-protocols \* | ||
31 | * pcre | ||
32 | * json-c | ||
33 | * pango | ||
34 | * cairo | ||
35 | * gdk-pixbuf2 (Ï€ÏοαιÏετικό: system tray) | ||
36 | * [scdoc] (Ï€ÏοαιÏετικό: man pages) \* | ||
37 | * git (Ï€ÏοαιÏετικό: πληÏοφοÏίες εκδώσεων) \* | ||
38 | |||
39 | _\*Compile-time dep_ | ||
40 | |||
41 | ΤÏÎξτε αυτά τα commands: | ||
42 | |||
43 | meson build/ | ||
44 | ninja -C build/ | ||
45 | sudo ninja -C build/ install | ||
46 | |||
47 | Σε συστήματα χωÏίς logind ή seatd, Ï€ÏÎπει να κάνετε suid το sway binary: | ||
48 | |||
49 | sudo chmod a+s /usr/local/bin/sway | ||
50 | |||
51 | Το Sway θα κάνει drop root δικαιώματα λίγο μετά την εκκίνηση. | ||
52 | |||
53 | ## Configuration | ||
54 | |||
55 | Εάν ήδη χÏησιμοποιήτε το i3, αντιγÏάψτε το i3 config σας στο `~/.config/sway/config` και | ||
56 | θα δουλÎψει out of the box. Αλλιώς, αντιγÏάψτε το sample configuration αÏχείο στο | ||
57 | `~/.config/sway/config`. Το οποίο συνήθως βÏίσκεται στο `/etc/sway/config`. | ||
58 | Κάντε run `man 5 sway` για πληÏοφοÏίες Ï„Î¿Ï configuration. | ||
59 | |||
60 | ## ΤÏÎχοντας | ||
61 | |||
62 | ΤÏÎξτε `sway` από Îνα TTY. ΜεÏίκα display managers μποÏεί να δουλÎψουν αλλά δÎν είναι συμβατά με | ||
63 | το sway (το gdm γνωÏίζεται να δουλÎβει σχετικά καλά). | ||
64 | |||
65 | [i3]: https://i3wm.org/ | ||
66 | [Wayland]: http://wayland.freedesktop.org/ | ||
67 | [FAQ]: https://github.com/swaywm/sway/wiki | ||
68 | [IRC channel]: https://web.libera.chat/gamja/?channels=#sway | ||
69 | [E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48 | ||
70 | [GitHub releases]: https://github.com/swaywm/sway/releases | ||
71 | [Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup | ||
72 | [wlroots]: https://github.com/swaywm/wlroots | ||
73 | [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 00000000..75999071 --- /dev/null +++ b/README.hu.md | |||
@@ -0,0 +1,77 @@ | |||
1 | # sway | ||
2 | |||
3 | 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). | ||
4 | |||
5 | ## Csomag aláÃrások | ||
6 | |||
7 | A kiadott csomagok az [E88F5E48] kulccsal vannak aláÃrva és [GitHub-on][GitHub releases] publikálva. | ||
8 | |||
9 | ## TelepÃtés | ||
10 | |||
11 | ### Csomagból | ||
12 | |||
13 | A Sway sok disztribúció csomagkezelőjéből elérhető, próbáld meg a "sway" | ||
14 | csomagot telepÃteni az általad használt eszközzel. | ||
15 | |||
16 | Ha szeretnél csomagot készÃteni a saját disztribúciódhoz, ugorj be az IRC | ||
17 | csatornára, vagy küldj levelet a sir@cmpwn.com cÃmre tanácsokért. | ||
18 | |||
19 | ### FordÃtás forráskódból | ||
20 | |||
21 | Olvasd el [ezt a wiki oldalt][Development setup], ha szeretnéd tesztelési vagy | ||
22 | fejlesztési célokból lefordÃtani az aktuális (HEAD) állapotát a `sway`-nek és a | ||
23 | `wlroots`-nak. | ||
24 | |||
25 | TelepÃtsd a függÅ‘ségeket: | ||
26 | |||
27 | * meson \* | ||
28 | * [wlroots] | ||
29 | * wayland | ||
30 | * wayland-protocols \* | ||
31 | * pcre | ||
32 | * json-c | ||
33 | * pango | ||
34 | * cairo | ||
35 | * gdk-pixbuf2 (opcionális: system tray) | ||
36 | * [scdoc] (opcionális: man pages) \* | ||
37 | * git (opcionális: version info) \* | ||
38 | |||
39 | _\*FordÃtásidejű függÅ‘ség_ | ||
40 | |||
41 | Futtasd ezeket a parancsokat: | ||
42 | |||
43 | meson build | ||
44 | ninja -C build | ||
45 | sudo ninja -C build install | ||
46 | |||
47 | Ha `logind` nélküli rendszert használsz, akkor be kell állÃtanod a `suid` bitet | ||
48 | a futtaható állományon: | ||
49 | |||
50 | sudo chmod a+s /usr/local/bin/sway | ||
51 | |||
52 | A Sway indulás után nem sokkal el fogja engedni a root jogosultságait. | ||
53 | |||
54 | ## Konfiguráció | ||
55 | |||
56 | Ha elÅ‘zÅ‘leg i3-mat használtál, akkor átmásolhatod az i3 beállÃtásaidat a | ||
57 | `~/.config/sway/config` file-ba és ugyanúgy működni fognak. Egyéb esetben másold | ||
58 | le kiindulási alapnak a mintát, ami általában az `etc/sway/config` elérési | ||
59 | útvonalon található. | ||
60 | Futtasd a `man 5 sway` parancsot további információért a konfigurációval | ||
61 | kapcsolatban. | ||
62 | |||
63 | ## Futtatás | ||
64 | |||
65 | Futtasd a `sway` parancsot egy TTY felületről. Néhány bejelentkezéskezelő | ||
66 | (display manager) működhet, de alapvetően nem támogatottak a sway által. (A | ||
67 | gdm-ről ismeretes, hogy egész jól működik.) | ||
68 | |||
69 | [i3]: https://i3wm.org/ | ||
70 | [Wayland]: http://wayland.freedesktop.org/ | ||
71 | [FAQ]: https://github.com/swaywm/sway/wiki | ||
72 | [IRC channel]: https://web.libera.chat/gamja/?channels=#sway | ||
73 | [E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48 | ||
74 | [GitHub releases]: https://github.com/swaywm/sway/releases | ||
75 | [Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup | ||
76 | [wlroots]: https://github.com/swaywm/wlroots | ||
77 | [scdoc]: https://git.sr.ht/~sircmpwn/scdoc | ||
diff --git a/README.ir.md b/README.ir.md new file mode 100644 index 00000000..890a0fd2 --- /dev/null +++ b/README.ir.md | |||
@@ -0,0 +1,70 @@ | |||
1 | <div dir="rtl"> | ||
2 | |||
3 | # sway | ||
4 | |||
5 | sway یک کامپوزیتور الهام گرÙته از [i3](https://i3wm.org/) بر روی [Wayland](http://wayland.freedesktop.org/) است. [سوال‌های متداول](https://github.com/swaywm/sway/wiki) را بخوانید. در [کانال | ||
6 | IRC](http://web.libera.chat/gamja/?channels=sway&uio=d4) عضو شوید (#sway sur | ||
7 | irc.libera.chat). | ||
8 | |||
9 | برای Øمایت از تیم توسعه sway به [صÙØÙ‡ | ||
10 | Patreon با نام کاربری SirCmpwn](https://patreon.com/sircmpwn) مراجعه کنید. | ||
11 | |||
12 | ## امضای نسخه‌ها | ||
13 | |||
14 | امضای نسخه‌ها با [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) در [GitHub](https://github.com/swaywm/sway/releases) منتشر می‌شود. | ||
15 | |||
16 | ## شیوه نصب | ||
17 | |||
18 | ### از بسته‌های رسمی | ||
19 | |||
20 | sway در بسته‌های رسمی توزیع‌های مختل٠وجود دارد. بسته «sway» را نصب کنید. در صورتی Ú©Ù‡ بسته رسمی وجود نداشت، برای آگاهی بیشتر درباره نصب روی توزیعتان به این [صÙØÙ‡ راهنما](https://github.com/swaywm/sway/wiki/Unsupported-packages) مراجعه کنید. | ||
21 | |||
22 | اگر به ایجاد بسته sway برای توزیعتان علاقه‌مند هستید، از کانال IRC استÙاده کنید یا به sir@cmpwn.com ایمیل بزنید. | ||
23 | |||
24 | ### کامپایل کردن کد | ||
25 | |||
26 | چنانچه می‌خواهید آخرین نسخه کد sway Ùˆ wlroots را برای آزمایش یا توسعه بسازید به این [صÙØÙ‡ راهنما](https://github.com/swaywm/sway/wiki/Development-Setup) مراجعه کنید. | ||
27 | |||
28 | بسته‌های مورد نیاز: | ||
29 | |||
30 | * meson \* | ||
31 | * [wlroots](https://github.com/swaywm/wlroots) | ||
32 | * wayland | ||
33 | * wayland-protocols \* | ||
34 | * pcre | ||
35 | * json-c | ||
36 | * pango | ||
37 | * cairo | ||
38 | * gdk-pixbuf2 (انتخابی: برای system tray) | ||
39 | * [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (انتخابی: برای صÙØه‌های راهنما) \* | ||
40 | * git (انتخابی: برای اطلاع در خصوص نسخه‌ها) \* | ||
41 | |||
42 | _\*نیازمندی‌های زمان کامپایل برنامه_ | ||
43 | |||
44 | این Ùرمان‌ها را اجرا کنید: | ||
45 | </div> | ||
46 | |||
47 | meson build | ||
48 | ninja -C build | ||
49 | sudo ninja -C build install | ||
50 | |||
51 | <div dir="rtl"> | ||
52 | |||
53 | روی سیستم‌های بدون logindØŒ باید Ùرمان زیر را برای suid کردن باینری sway اجرا کنید: | ||
54 | </div> | ||
55 | |||
56 | sudo chmod a+s /usr/local/bin/sway | ||
57 | |||
58 | <div dir="rtl"> | ||
59 | sway پس از startup مجوزهای دسترسی root را رها می‌کند. | ||
60 | |||
61 | ### شخصی سازی و تنظیمات | ||
62 | |||
63 | اگر در Øال Øاضر از i3 استÙاده می‌کنید، تنظیمات i3 خودتان را در Ùایل ‪`~/.config/sway/config`‬ Ú©Ù¾ÛŒ کنید Ùˆ بدون نیاز به تغییر کار خواهد کرد. در غیر این‌صورت، Ùایل نمونه تنظیمات را استÙاده کنید. این Ùایل عموما در ‪`/etc/sway/config`‬ قرار دارد. برای آگاهی بیشتر `man 5 sway` را اجرا کنید. | ||
64 | |||
65 | ## اجرا | ||
66 | |||
67 | در Ù…Øیط TTY کاÙیست `sway` را اجرا کنید. ممکن است ابزارهای مدیریت نمایشگری نیز برای این کار وجود داشته باشند اما از طر٠sway پشتیبانی نمی‌شوند (gdm عملکرد خوبی در این زمینه دارد). | ||
68 | |||
69 | </div> | ||
70 | |||
diff --git a/README.ja.md b/README.ja.md index fa28f3da..7af54fb2 100644 --- a/README.ja.md +++ b/README.ja.md | |||
@@ -2,7 +2,7 @@ | |||
2 | 2 | ||
3 | Swayã¯[i3](https://i3wm.org/)互æ›ãª[Wayland](http://wayland.freedesktop.org/)コンãƒã‚¸ã‚¿ã§ã™ã€‚ | 3 | Swayã¯[i3](https://i3wm.org/)互æ›ãª[Wayland](http://wayland.freedesktop.org/)コンãƒã‚¸ã‚¿ã§ã™ã€‚ |
4 | [FAQ](https://github.com/swaywm/sway/wiki)ã‚‚åˆã‚ã›ã¦ã”覧ãã ã•ã„。 | 4 | [FAQ](https://github.com/swaywm/sway/wiki)ã‚‚åˆã‚ã›ã¦ã”覧ãã ã•ã„。 |
5 | [IRC ãƒãƒ£ãƒ³ãƒãƒ«](http://webchat.freenode.net/?channels=sway&uio=d4) (irc.freenode.netã®#sway)ã‚‚ã‚ã‚Šã¾ã™ã€‚ | 5 | [IRC ãƒãƒ£ãƒ³ãƒãƒ«](https://web.libera.chat/gamja/?channels=#sway) (irc.libera.chatã®#sway)ã‚‚ã‚ã‚Šã¾ã™ã€‚ |
6 | 6 | ||
7 | [![](https://sr.ht/ICd5.png)](https://sr.ht/ICd5.png) | 7 | [![](https://sr.ht/ICd5.png)](https://sr.ht/ICd5.png) |
8 | 8 | ||
@@ -12,7 +12,7 @@ SirCmpwnã¯ã€æ—¥æœ¬èªžã§ã®ã‚µãƒãƒ¼ãƒˆã‚’IRCã¨GitHubã§è¡Œã„ã¾ã™ã€‚タイ | |||
12 | 12 | ||
13 | ## リリースã®ç½²å | 13 | ## リリースã®ç½²å |
14 | 14 | ||
15 | Swayã®ãƒªãƒªãƒ¼ã‚¹ã¯[B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)ã§ç½²åã•ã‚Œã€[GitHub](https://github.com/swaywm/sway/releases)ã§å…¬é–‹ã•ã‚Œã¦ã„ã¾ã™ã€‚ | 15 | Swayã®ãƒªãƒªãƒ¼ã‚¹ã¯[E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48)ã§ç½²åã•ã‚Œã€[GitHub](https://github.com/swaywm/sway/releases)ã§å…¬é–‹ã•ã‚Œã¦ã„ã¾ã™ã€‚ |
16 | 16 | ||
17 | ## インストール | 17 | ## インストール |
18 | 18 | ||
diff --git a/README.ko.md b/README.ko.md index 9c3dd323..76ce2f4d 100644 --- a/README.ko.md +++ b/README.ko.md | |||
@@ -1,11 +1,11 @@ | |||
1 | # sway | 1 | # sway |
2 | 2 | ||
3 | sway는 [i3](https://i3wm.org/)-호환 [Wayland](http://wayland.freedesktop.org/) ì»´í¬ì§€í„°ìž…니다. | 3 | sway는 [i3](https://i3wm.org/)-호환 [Wayland](http://wayland.freedesktop.org/) ì»´í¬ì§€í„°ìž…니다. |
4 | [FAQ](https://github.com/swaywm/sway/wiki)를 ì½ì–´ë³´ì„¸ìš”. [IRC 채ë„](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on irc.freenode.net)ë„ ìžˆìŠµë‹ˆë‹¤. | 4 | [FAQ](https://github.com/swaywm/sway/wiki)를 ì½ì–´ë³´ì„¸ìš”. [IRC 채ë„](https://web.libera.chat/gamja/?channels=#sway) (#sway on irc.libera.chat)ë„ ìžˆìŠµë‹ˆë‹¤. |
5 | 5 | ||
6 | ## 릴리즈 서명 | 6 | ## 릴리즈 서명 |
7 | 7 | ||
8 | 릴리즈는 [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)ì—ì„œ 서명ë˜ê³ , | 8 | 릴리즈는 [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48)ì—ì„œ 서명ë˜ê³ , |
9 | [GitHubì—ì„œ](https://github.com/swaywm/sway/releases) 공개ë˜ê³ 있습니다. | 9 | [GitHubì—ì„œ](https://github.com/swaywm/sway/releases) 공개ë˜ê³ 있습니다. |
10 | 10 | ||
11 | ## 설치 | 11 | ## 설치 |
@@ -1,9 +1,9 @@ | |||
1 | # sway | 1 | # sway |
2 | 2 | ||
3 | **[English][en]** - [日本語][ja] - [Français][fr] - [УкраїнÑька][uk] - [Español][es] - [Polski][pl] - [ä¸æ–‡-简体][zh-CN] - [Deutsch][de] - [Nederlands][nl] - [РуÑÑкий][ru] - [ä¸æ–‡-ç¹é«”][zh-TW] - [Português][pt] - [Danish][dk] - [í•œêµì–´][ko] - [Română][ro] | 3 | **[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] |
4 | 4 | ||
5 | sway is an [i3]-compatible [Wayland] compositor. Read the [FAQ]. Join the | 5 | sway is an [i3]-compatible [Wayland] compositor. Read the [FAQ]. Join the |
6 | [IRC channel] \(#sway on irc.freenode.net). | 6 | [IRC channel] \(#sway on irc.libera.chat). |
7 | 7 | ||
8 | ## Release Signatures | 8 | ## Release Signatures |
9 | 9 | ||
@@ -16,9 +16,6 @@ Releases are signed with [E88F5E48] and published [on GitHub][GitHub releases]. | |||
16 | Sway is available in many distributions. Try installing the "sway" package for | 16 | Sway is available in many distributions. Try installing the "sway" package for |
17 | yours. | 17 | yours. |
18 | 18 | ||
19 | If you're interested in packaging sway for your distribution, stop by the IRC | ||
20 | channel or shoot an email to sir@cmpwn.com for advice. | ||
21 | |||
22 | ### Compiling from Source | 19 | ### Compiling from Source |
23 | 20 | ||
24 | Check out [this wiki page][Development setup] if you want to build the HEAD of | 21 | Check out [this wiki page][Development setup] if you want to build the HEAD of |
@@ -38,15 +35,15 @@ Install dependencies: | |||
38 | * [scdoc] (optional: man pages) \* | 35 | * [scdoc] (optional: man pages) \* |
39 | * git (optional: version info) \* | 36 | * git (optional: version info) \* |
40 | 37 | ||
41 | _\*Compile-time dep_ | 38 | _\* Compile-time dep_ |
42 | 39 | ||
43 | Run these commands: | 40 | Run these commands: |
44 | 41 | ||
45 | meson build | 42 | meson build/ |
46 | ninja -C build | 43 | ninja -C build/ |
47 | sudo ninja -C build install | 44 | sudo ninja -C build/ install |
48 | 45 | ||
49 | On systems without logind, you need to suid the sway binary: | 46 | On systems without logind nor seatd, you need to suid the sway binary: |
50 | 47 | ||
51 | sudo chmod a+s /usr/local/bin/sway | 48 | sudo chmod a+s /usr/local/bin/sway |
52 | 49 | ||
@@ -79,10 +76,14 @@ sway (gdm is known to work fairly well). | |||
79 | [dk]: https://github.com/swaywm/sway/blob/master/README.dk.md | 76 | [dk]: https://github.com/swaywm/sway/blob/master/README.dk.md |
80 | [ko]: https://github.com/swaywm/sway/blob/master/README.ko.md | 77 | [ko]: https://github.com/swaywm/sway/blob/master/README.ko.md |
81 | [ro]: https://github.com/swaywm/sway/blob/master/README.ro.md | 78 | [ro]: https://github.com/swaywm/sway/blob/master/README.ro.md |
79 | [hu]: https://github.com/swaywm/sway/blob/master/README.hu.md | ||
80 | [tr]: https://github.com/swaywm/sway/blob/master/README.tr.md | ||
81 | [ir]: https://github.com/swaywm/sway/blob/master/README.ir.md | ||
82 | [gr]: https://github.com/swaywm/sway/blob/master/README.gr.md | ||
82 | [i3]: https://i3wm.org/ | 83 | [i3]: https://i3wm.org/ |
83 | [Wayland]: http://wayland.freedesktop.org/ | 84 | [Wayland]: http://wayland.freedesktop.org/ |
84 | [FAQ]: https://github.com/swaywm/sway/wiki | 85 | [FAQ]: https://github.com/swaywm/sway/wiki |
85 | [IRC channel]: http://webchat.freenode.net/?channels=sway&uio=d4 | 86 | [IRC channel]: https://web.libera.chat/gamja/?channels=#sway |
86 | [E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48 | 87 | [E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48 |
87 | [GitHub releases]: https://github.com/swaywm/sway/releases | 88 | [GitHub releases]: https://github.com/swaywm/sway/releases |
88 | [Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup | 89 | [Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup |
diff --git a/README.nl.md b/README.nl.md index 86ebe398..3351db39 100644 --- a/README.nl.md +++ b/README.nl.md | |||
@@ -2,12 +2,12 @@ | |||
2 | 2 | ||
3 | Sway is een [i3](https://i3wm.org/)-compatibele [Wayland](http://wayland.freedesktop.org/) compositor. | 3 | Sway is een [i3](https://i3wm.org/)-compatibele [Wayland](http://wayland.freedesktop.org/) compositor. |
4 | Lees de [FAQ](https://github.com/swaywm/sway/wiki). Word lid van het [IRC | 4 | Lees de [FAQ](https://github.com/swaywm/sway/wiki). Word lid van het [IRC |
5 | kanaal](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway op | 5 | kanaal](https://web.libera.chat/gamja/?channels=#sway) (#sway op |
6 | irc.freenode.net). | 6 | irc.libera.chat). |
7 | 7 | ||
8 | ## Releasehandtekeningen | 8 | ## Releasehandtekeningen |
9 | 9 | ||
10 | Releases worden ondertekend met [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) | 10 | Releases worden ondertekend met [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48) |
11 | en gepubliceerd [op GitHub](https://github.com/swaywm/sway/releases). | 11 | en gepubliceerd [op GitHub](https://github.com/swaywm/sway/releases). |
12 | 12 | ||
13 | ## Installatie | 13 | ## Installatie |
diff --git a/README.pl.md b/README.pl.md index b63b8567..da987b7c 100644 --- a/README.pl.md +++ b/README.pl.md | |||
@@ -1,12 +1,12 @@ | |||
1 | # sway | 1 | # sway |
2 | 2 | ||
3 | sway jest kompozytorem [Wayland](http://wayland.freedesktop.org/) kompatybilnym z [i3](https://i3wm.org/). | 3 | sway jest kompozytorem [Wayland](http://wayland.freedesktop.org/) kompatybilnym z [i3](https://i3wm.org/). |
4 | Przeczytaj [FAQ](https://github.com/swaywm/sway/wiki). Dołącz do [kanału IRC](http://webchat.freenode.net/?channels=sway&uio=d4) | 4 | Przeczytaj [FAQ](https://github.com/swaywm/sway/wiki). Dołącz do [kanału IRC](https://web.libera.chat/gamja/?channels=#sway) |
5 | (#sway na irc.freenode.net). | 5 | (#sway na irc.libera.chat). |
6 | 6 | ||
7 | ## Podpisy cyfrowe wydań | 7 | ## Podpisy cyfrowe wydań |
8 | 8 | ||
9 | Wydania sÄ… podpisywane przy pomocy klucza [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) | 9 | Wydania sÄ… podpisywane przy pomocy klucza [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48) |
10 | i publikowane [na GitHubie](https://github.com/swaywm/sway/releases). | 10 | i publikowane [na GitHubie](https://github.com/swaywm/sway/releases). |
11 | 11 | ||
12 | ## Instalacja | 12 | ## Instalacja |
diff --git a/README.pt.md b/README.pt.md index ad7cab65..7d449ef3 100644 --- a/README.pt.md +++ b/README.pt.md | |||
@@ -2,12 +2,12 @@ | |||
2 | 2 | ||
3 | O sway é um compositor do [Wayland](http://wayland.freedesktop.org/) compatÃvel com o [i3](https://i3wm.org/). | 3 | O sway é um compositor do [Wayland](http://wayland.freedesktop.org/) compatÃvel com o [i3](https://i3wm.org/). |
4 | Leia o [FAQ](https://github.com/swaywm/sway/wiki). Junte-se ao [canal do | 4 | Leia o [FAQ](https://github.com/swaywm/sway/wiki). Junte-se ao [canal do |
5 | IRC](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway em | 5 | IRC](https://web.libera.chat/gamja/?channels=#sway) (#sway em |
6 | irc.freenode.net). | 6 | irc.libera.chat). |
7 | 7 | ||
8 | ## Assinatura das versões | 8 | ## Assinatura das versões |
9 | 9 | ||
10 | As versões são assinadas com [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) | 10 | As versões são assinadas com [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48) |
11 | e publicadas [no GitHub](https://github.com/swaywm/sway/releases). | 11 | e publicadas [no GitHub](https://github.com/swaywm/sway/releases). |
12 | 12 | ||
13 | ## Instalação | 13 | ## Instalação |
diff --git a/README.ro.md b/README.ro.md index dd895b56..79524b79 100644 --- a/README.ro.md +++ b/README.ro.md | |||
@@ -1,11 +1,11 @@ | |||
1 | # sway | 1 | # sway |
2 | 2 | ||
3 | sway este un compositor pentru [Wayland](http://wayland.freedesktop.org/) compatibil cu [i3](https://i3wm.org/). | 3 | sway este un compositor pentru [Wayland](http://wayland.freedesktop.org/) compatibil cu [i3](https://i3wm.org/). |
4 | 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). | 4 | 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). |
5 | 5 | ||
6 | ## Semnarea digitală | 6 | ## Semnarea digitală |
7 | 7 | ||
8 | Noile versiuni sunt semnate cu [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) | 8 | Noile versiuni sunt semnate cu [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48) |
9 | și postate [pe GitHub](https://github.com/swaywm/sway/releases). | 9 | și postate [pe GitHub](https://github.com/swaywm/sway/releases). |
10 | 10 | ||
11 | ## Instalare | 11 | ## Instalare |
diff --git a/README.ru.md b/README.ru.md index a870ec89..70396905 100644 --- a/README.ru.md +++ b/README.ru.md | |||
@@ -1,42 +1,41 @@ | |||
1 | # sway | 1 | # sway |
2 | 2 | ||
3 | sway - Ñто [i3](https://i3wm.org/)-ÑовмеÑтимый композитор [Wayland](http://wayland.freedesktop.org/). | 3 | sway - Ñто [i3]-ÑовмеÑтимый композитор [Wayland]. |
4 | Больше информации в [FAQ](https://github.com/swaywm/sway/wiki). ПриÑоединÑйтеÑÑŒ к | 4 | Больше информации в [FAQ]. ПриÑоединÑйтеÑÑŒ к |
5 | [IRC-каналу](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway на | 5 | [IRC-каналу][IRC channel] (#sway на |
6 | irc.freenode.net). | 6 | irc.libera.chat). |
7 | 7 | ||
8 | ## ПодпиÑи релизов | 8 | ## ПодпиÑи релизов |
9 | 9 | ||
10 | Релизы подпиÑываютÑÑ ÐºÐ»ÑŽÑ‡Ð¾Ð¼ [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) | 10 | Релизы подпиÑываютÑÑ ÐºÐ»ÑŽÑ‡Ð¾Ð¼ [E88F5E48] и публикуютÑÑ [на GitHub][GitHub releases]. |
11 | и публикуютÑÑ [на GitHub](https://github.com/swaywm/sway/releases). | ||
12 | 11 | ||
13 | ## УÑтановка | 12 | ## УÑтановка |
14 | 13 | ||
15 | ### Из репозиториев | 14 | ### Из репозиториев |
16 | 15 | ||
17 | sway доÑтупен во многих диÑтрибутивах. Попробуйте уÑтановить пакет "sway". | 16 | Sway доÑтупен во многих диÑтрибутивах. Попробуйте уÑтановить пакет "sway". |
18 | ЕÑли он вдруг недоÑтупен, проверьте [Ñту Ñтраницу на wiki](https://github.com/swaywm/sway/wiki/Unsupported-packages) | ||
19 | Ð´Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ð¸ о подробноÑÑ‚ÑÑ… уÑтановки Ð´Ð»Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ | ||
20 | диÑтрибутива. | ||
21 | 17 | ||
22 | ЕÑли вы заинтереÑованы поддерживать sway в вашем диÑтрибутиве, заглÑните в наш IRC-канал | 18 | ЕÑли Ð²Ð°Ñ Ð¸Ð½Ñ‚ÐµÑ€ÐµÑует Ñоздание пакета sway Ð´Ð»Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ диÑтрибутива, зайдите на [IRC-канал][IRC channel] |
23 | или обратитеÑÑŒ на sir@cmpwn.com за Ñоветом. | 19 | или отправьте пиÑьмо на sir@cmpwn.com за Ñоветом. |
24 | 20 | ||
25 | ### Сборка из иÑходников | 21 | ### Сборка из иÑходников |
26 | 22 | ||
23 | ПоÑетите [Ñту Ñтраницу на вики][Development setup], еÑли вы хотите поÑтроить поÑледнюю верÑию | ||
24 | sway и wlroots Ð´Ð»Ñ Ñ‚ÐµÑÑ‚Ð¸Ñ€Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¸Ð»Ð¸ разработки. | ||
25 | |||
27 | УÑтановите завиÑимоÑти: | 26 | УÑтановите завиÑимоÑти: |
28 | 27 | ||
29 | * meson \* | 28 | * meson \* |
30 | * [wlroots](https://github.com/swaywm/wlroots) | 29 | * [wlroots] |
31 | * wayland | 30 | * wayland |
32 | * wayland-protocols \* | 31 | * wayland-protocols \* |
33 | * pcre | 32 | * pcre |
34 | * json-c | 33 | * json-c |
35 | * pango | 34 | * pango |
36 | * cairo | 35 | * cairo |
37 | * gdk-pixbuf2 (необÑзательно: Ð´Ð»Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹ треÑ) | 36 | * gdk-pixbuf2 (опционально: Ð´Ð»Ñ Ñ€Ð°Ð±Ð¾Ñ‚Ñ‹ треÑ) |
38 | * [scdoc](https://git.sr.ht/~sircmpwn/scdoc) (необÑзательно: Ð´Ð»Ñ Ñборки man-Ñтраниц) \* | 37 | * [scdoc] (опционально: Ð´Ð»Ñ man-Ñтраниц) \* |
39 | * git \* | 38 | * git (опционально: Ð´Ð»Ñ Ð¸Ð½Ñ„Ð¾Ñ€Ð¼Ð°Ñ†Ð¸Ð¸ о верÑии) \* |
40 | 39 | ||
41 | _\*ЗавиÑимоÑти Ð´Ð»Ñ Ñборки_ | 40 | _\*ЗавиÑимоÑти Ð´Ð»Ñ Ñборки_ |
42 | 41 | ||
@@ -63,3 +62,13 @@ sway ÑброÑит root-права при запуÑке. | |||
63 | 62 | ||
64 | Выполните команду `sway` прÑмо из TTY. Ðекоторые диÑплейные менеджеры могут работать, но они не поддерживаютÑÑ Ñо Ñтороны | 63 | Выполните команду `sway` прÑмо из TTY. Ðекоторые диÑплейные менеджеры могут работать, но они не поддерживаютÑÑ Ñо Ñтороны |
65 | sway (gdm работает довольно неплохо). | 64 | sway (gdm работает довольно неплохо). |
65 | |||
66 | [i3]: https://i3wm.org/ | ||
67 | [Wayland]: http://wayland.freedesktop.org/ | ||
68 | [FAQ]: https://github.com/swaywm/sway/wiki | ||
69 | [IRC channel]: https://web.libera.chat/gamja/?channels=#sway | ||
70 | [E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48 | ||
71 | [GitHub releases]: https://github.com/swaywm/sway/releases | ||
72 | [Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup | ||
73 | [wlroots]: https://github.com/swaywm/wlroots | ||
74 | [scdoc]: https://git.sr.ht/~sircmpwn/scdoc | ||
diff --git a/README.tr.md b/README.tr.md new file mode 100644 index 00000000..c0f72d72 --- /dev/null +++ b/README.tr.md | |||
@@ -0,0 +1,68 @@ | |||
1 | # sway | ||
2 | |||
3 | |||
4 | Sway, [i3]-uyumlu bir [Wayland] dizgicisidir. [SSS][FAQ]'yi okuyun. | ||
5 | [IRC kanalı][IRC channel]na katılın \(irc.libera.chat'te #sway (İngilizce)). | ||
6 | |||
7 | ## Sürüm imzaları | ||
8 | |||
9 | Sürümler [E88F5E48] ile imzalandı ve [GitHub][GitHub releases]'da yayınlandı. | ||
10 | |||
11 | ## Kurulum | ||
12 | |||
13 | ### Paketler ile | ||
14 | |||
15 | Sway birçok dağıtımda mevcuttur. Sizinki için "sway" paketini yüklemeyi deneyin. | ||
16 | |||
17 | 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. | ||
18 | |||
19 | ### Kaynak koddan derleme | ||
20 | |||
21 | 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. | ||
22 | |||
23 | Aşağıdaki bağımlılıkları yükleyin: | ||
24 | |||
25 | * meson \* | ||
26 | * [wlroots] | ||
27 | * wayland | ||
28 | * wayland-protocols \* | ||
29 | * pcre | ||
30 | * json-c | ||
31 | * pango | ||
32 | * cairo | ||
33 | * gdk-pixbuf2 (isteğe bağlı: system tray) | ||
34 | * [scdoc] (isteğe bağlı: man pages) \* | ||
35 | * git (isteğe bağlı: version info) \* | ||
36 | |||
37 | _\*Derleme-anı bağımlılıkları_ | ||
38 | |||
39 | Şu komutları çalıştırın: | ||
40 | |||
41 | meson build | ||
42 | ninja -C build | ||
43 | sudo ninja -C build install | ||
44 | |||
45 | logind olmayan sistemlerde, sway ikilisine (binary) izin vermeniz (suid) gerekir: | ||
46 | |||
47 | sudo chmod a+s /usr/local/bin/sway | ||
48 | |||
49 | Sway, başlangıçtan kısa bir süre sonra kök(root) izinlerini bırakacaktır. | ||
50 | |||
51 | ## Yapılandırma | ||
52 | |||
53 | 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. | ||
54 | Yapılandırma hakkında bilgi almak için `man 5 sway` komutunu çalıştırın. | ||
55 | |||
56 | ## Çalıştırma | ||
57 | |||
58 | 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.) | ||
59 | |||
60 | [i3]: https://i3wm.org/ | ||
61 | [Wayland]: http://wayland.freedesktop.org/ | ||
62 | [FAQ]: https://github.com/swaywm/sway/wiki | ||
63 | [IRC channel]: https://web.libera.chat/gamja/?channels=#sway | ||
64 | [E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48 | ||
65 | [GitHub releases]: https://github.com/swaywm/sway/releases | ||
66 | [Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup | ||
67 | [wlroots]: https://github.com/swaywm/wlroots | ||
68 | [scdoc]: https://git.sr.ht/~sircmpwn/scdoc | ||
diff --git a/README.uk.md b/README.uk.md index 95047cb8..3d7402de 100644 --- a/README.uk.md +++ b/README.uk.md | |||
@@ -2,8 +2,8 @@ | |||
2 | 2 | ||
3 | Sway це ÑуміÑний з [i3](https://i3wm.org/) композитор [Wayland](http://wayland.freedesktop.org/). | 3 | Sway це ÑуміÑний з [i3](https://i3wm.org/) композитор [Wayland](http://wayland.freedesktop.org/). |
4 | ОзнайомтеÑÑŒ з [ЧаПами](https://github.com/swaywm/sway/wiki). ПриєднуйтеÑÑŒ до [Ñпільноти в | 4 | ОзнайомтеÑÑŒ з [ЧаПами](https://github.com/swaywm/sway/wiki). ПриєднуйтеÑÑŒ до [Ñпільноти в |
5 | IRC](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway на | 5 | IRC](https://web.libera.chat/gamja/?channels=#sway) (#sway на |
6 | irc.freenode.net). | 6 | irc.libera.chat). |
7 | 7 | ||
8 | ## Підтримка українÑькою мовою | 8 | ## Підтримка українÑькою мовою |
9 | 9 | ||
@@ -15,7 +15,7 @@ Hummer12007 у IRC-Ñпільноті. Будьте терплÑчі, вам оР| |||
15 | 15 | ||
16 | ## ПідпиÑи випуÑків | 16 | ## ПідпиÑи випуÑків |
17 | 17 | ||
18 | ВипуÑки підпиÑані ключем [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) | 18 | ВипуÑки підпиÑані ключем [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48) |
19 | та публікуютьÑÑ Ð½Ð° Ñторінці [GitHub](https://github.com/swaywm/sway/releases). | 19 | та публікуютьÑÑ Ð½Ð° Ñторінці [GitHub](https://github.com/swaywm/sway/releases). |
20 | 20 | ||
21 | ## Ð’ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ | 21 | ## Ð’ÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð½Ñ |
diff --git a/README.zh-CN.md b/README.zh-CN.md index 9a3337ce..ecb46789 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md | |||
@@ -2,12 +2,12 @@ | |||
2 | 2 | ||
3 | sway 是和 [i3](https://i3wm.org/) 兼容的 [Wayland](http://wayland.freedesktop.org/) compositor. | 3 | sway 是和 [i3](https://i3wm.org/) 兼容的 [Wayland](http://wayland.freedesktop.org/) compositor. |
4 | 阅读 [FAQ](https://github.com/swaywm/sway/wiki). åŠ å…¥ [IRC | 4 | 阅读 [FAQ](https://github.com/swaywm/sway/wiki). åŠ å…¥ [IRC |
5 | 频é“](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on | 5 | 频é“](https://web.libera.chat/gamja/?channels=#sway) (#sway on |
6 | irc.freenode.net). | 6 | irc.libera.chat). |
7 | 7 | ||
8 | ## å‘布ç¾å | 8 | ## å‘布ç¾å |
9 | 9 | ||
10 | å‘布是以 [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) ç¾å | 10 | å‘布是以 [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48) ç¾å |
11 | 并å‘布在 [GitHub](https://github.com/swaywm/sway/releases). | 11 | 并å‘布在 [GitHub](https://github.com/swaywm/sway/releases). |
12 | 12 | ||
13 | ## 安装 | 13 | ## 安装 |
diff --git a/README.zh-TW.md b/README.zh-TW.md index 13a9d2f4..4fd656da 100644 --- a/README.zh-TW.md +++ b/README.zh-TW.md | |||
@@ -2,12 +2,12 @@ | |||
2 | 2 | ||
3 | sway 是一個與 [i3](https://i3wm.org/) 相容的 [Wayland](http://wayland.freedesktop.org/) compositor。 | 3 | sway 是一個與 [i3](https://i3wm.org/) 相容的 [Wayland](http://wayland.freedesktop.org/) compositor。 |
4 | 閱讀 [FAQ](https://github.com/swaywm/sway/wiki)。 åŠ å…¥ [IRC | 4 | 閱讀 [FAQ](https://github.com/swaywm/sway/wiki)。 åŠ å…¥ [IRC |
5 | é »é“](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on | 5 | é »é“](https://web.libera.chat/gamja/?channels=#sway) (#sway on |
6 | irc.freenode.net) | 6 | irc.libera.chat) |
7 | 7 | ||
8 | ## ç™¼è¡Œç°½ç« | 8 | ## ç™¼è¡Œç°½ç« |
9 | 9 | ||
10 | 所有發行的版本都會以 [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) 簽署 | 10 | 所有發行的版本都會以 [E88F5E48](https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48) 簽署 |
11 | 並發佈於 [GitHub](https://github.com/swaywm/sway/releases) | 11 | 並發佈於 [GitHub](https://github.com/swaywm/sway/releases) |
12 | 12 | ||
13 | ## å®‰è£ | 13 | ## å®‰è£ |
diff --git a/client/pool-buffer.c b/client/pool-buffer.c index fd500c49..ea31edd3 100644 --- a/client/pool-buffer.c +++ b/client/pool-buffer.c | |||
@@ -1,6 +1,6 @@ | |||
1 | #define _POSIX_C_SOURCE 200809 | 1 | #define _POSIX_C_SOURCE 200809 |
2 | #include <assert.h> | 2 | #include <assert.h> |
3 | #include <cairo/cairo.h> | 3 | #include <cairo.h> |
4 | #include <fcntl.h> | 4 | #include <fcntl.h> |
5 | #include <pango/pangocairo.h> | 5 | #include <pango/pangocairo.h> |
6 | #include <stdio.h> | 6 | #include <stdio.h> |
diff --git a/common/background-image.c b/common/background-image.c index de42e8e9..994a0805 100644 --- a/common/background-image.c +++ b/common/background-image.c | |||
@@ -1,6 +1,6 @@ | |||
1 | #include <assert.h> | 1 | #include <assert.h> |
2 | #include "background-image.h" | 2 | #include "background-image.h" |
3 | #include "cairo.h" | 3 | #include "cairo_util.h" |
4 | #include "log.h" | 4 | #include "log.h" |
5 | #if HAVE_GDK_PIXBUF | 5 | #if HAVE_GDK_PIXBUF |
6 | #include <gdk-pixbuf/gdk-pixbuf.h> | 6 | #include <gdk-pixbuf/gdk-pixbuf.h> |
diff --git a/common/cairo.c b/common/cairo.c index 403dcf49..7c59d48c 100644 --- a/common/cairo.c +++ b/common/cairo.c | |||
@@ -1,6 +1,6 @@ | |||
1 | #include <stdint.h> | 1 | #include <stdint.h> |
2 | #include <cairo/cairo.h> | 2 | #include <cairo.h> |
3 | #include "cairo.h" | 3 | #include "cairo_util.h" |
4 | 4 | ||
5 | void cairo_set_source_u32(cairo_t *cairo, uint32_t color) { | 5 | void cairo_set_source_u32(cairo_t *cairo, uint32_t color) { |
6 | cairo_set_source_rgba(cairo, | 6 | cairo_set_source_rgba(cairo, |
diff --git a/common/pango.c b/common/pango.c index fc3d0688..abc18281 100644 --- a/common/pango.c +++ b/common/pango.c | |||
@@ -1,4 +1,4 @@ | |||
1 | #include <cairo/cairo.h> | 1 | #include <cairo.h> |
2 | #include <pango/pangocairo.h> | 2 | #include <pango/pangocairo.h> |
3 | #include <stdarg.h> | 3 | #include <stdarg.h> |
4 | #include <stdbool.h> | 4 | #include <stdbool.h> |
@@ -6,7 +6,7 @@ | |||
6 | #include <stdio.h> | 6 | #include <stdio.h> |
7 | #include <stdlib.h> | 7 | #include <stdlib.h> |
8 | #include <string.h> | 8 | #include <string.h> |
9 | #include "cairo.h" | 9 | #include "cairo_util.h" |
10 | #include "log.h" | 10 | #include "log.h" |
11 | #include "stringop.h" | 11 | #include "stringop.h" |
12 | 12 | ||
@@ -109,7 +109,23 @@ void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, | |||
109 | free(buf); | 109 | free(buf); |
110 | } | 110 | } |
111 | 111 | ||
112 | void pango_printf(cairo_t *cairo, const char *font, | 112 | void get_text_metrics(const char *font, int *height, int *baseline) { |
113 | cairo_t *cairo = cairo_create(NULL); | ||
114 | PangoContext *pango = pango_cairo_create_context(cairo); | ||
115 | PangoFontDescription *description = pango_font_description_from_string(font); | ||
116 | // When passing NULL as a language, pango uses the current locale. | ||
117 | PangoFontMetrics *metrics = pango_context_get_metrics(pango, description, NULL); | ||
118 | |||
119 | *baseline = pango_font_metrics_get_ascent(metrics) / PANGO_SCALE; | ||
120 | *height = *baseline + pango_font_metrics_get_descent(metrics) / PANGO_SCALE; | ||
121 | |||
122 | pango_font_metrics_unref(metrics); | ||
123 | pango_font_description_free(description); | ||
124 | g_object_unref(pango); | ||
125 | cairo_destroy(cairo); | ||
126 | } | ||
127 | |||
128 | void render_text(cairo_t *cairo, const char *font, | ||
113 | double scale, bool markup, const char *fmt, ...) { | 129 | double scale, bool markup, const char *fmt, ...) { |
114 | va_list args; | 130 | va_list args; |
115 | va_start(args, fmt); | 131 | va_start(args, fmt); |
diff --git a/common/util.c b/common/util.c index 5ea94f48..199f3ee1 100644 --- a/common/util.c +++ b/common/util.c | |||
@@ -10,12 +10,6 @@ | |||
10 | #include "log.h" | 10 | #include "log.h" |
11 | #include "util.h" | 11 | #include "util.h" |
12 | 12 | ||
13 | uint32_t get_current_time_msec(void) { | ||
14 | struct timespec now; | ||
15 | clock_gettime(CLOCK_MONOTONIC, &now); | ||
16 | return now.tv_sec * 1000 + now.tv_nsec / 1000000; | ||
17 | } | ||
18 | |||
19 | int wrap(int i, int max) { | 13 | int wrap(int i, int max) { |
20 | return ((i % max) + max) % max; | 14 | return ((i % max) + max) % max; |
21 | } | 15 | } |
@@ -14,7 +14,7 @@ set $down j | |||
14 | set $up k | 14 | set $up k |
15 | set $right l | 15 | set $right l |
16 | # Your preferred terminal emulator | 16 | # Your preferred terminal emulator |
17 | set $term alacritty | 17 | set $term foot |
18 | # Your preferred application launcher | 18 | # Your preferred application launcher |
19 | # Note: pass the final command to swaymsg so that the resulting window can be opened | 19 | # Note: pass the final command to swaymsg so that the resulting window can be opened |
20 | # on the original workspace that the command was run on. | 20 | # on the original workspace that the command was run on. |
@@ -205,7 +205,7 @@ bar { | |||
205 | 205 | ||
206 | # When the status_command prints a new line to stdout, swaybar updates. | 206 | # When the status_command prints a new line to stdout, swaybar updates. |
207 | # The default just shows the current date and time. | 207 | # The default just shows the current date and time. |
208 | status_command while date +'%Y-%m-%d %l:%M:%S %p'; do sleep 1; done | 208 | status_command while date +'%Y-%m-%d %I:%M:%S %p'; do sleep 1; done |
209 | 209 | ||
210 | colors { | 210 | colors { |
211 | statusline #ffffff | 211 | statusline #ffffff |
diff --git a/contrib/_incr_version b/contrib/_incr_version deleted file mode 100755 index a4fa2654..00000000 --- a/contrib/_incr_version +++ /dev/null | |||
@@ -1,21 +0,0 @@ | |||
1 | #!/bin/sh -eu | ||
2 | old_version="$1" | ||
3 | new_version="$2" | ||
4 | |||
5 | if [ "$new_version" != "${new_version#v}" ] | ||
6 | then | ||
7 | echo "Error: The new version shouldn't be prefixed with a \"v\"." >&2 | ||
8 | exit 1 | ||
9 | fi | ||
10 | |||
11 | sed -i meson.build -e "s/^ version: .*#release_version/ version: '$new_version', #release_version/g" | ||
12 | |||
13 | printf "Minimum wlroots version? " | ||
14 | read wlr_version_min | ||
15 | printf "Maximum wlroots version? " | ||
16 | read wlr_version_max | ||
17 | |||
18 | sed -i meson.build -e "s/wlroots_version =.*/wlroots_version = ['>=$wlr_version_min', '<$wlr_version_max']/" | ||
19 | |||
20 | git add meson.build | ||
21 | git commit -m "Update version to $new_version" | ||
diff --git a/contrib/autoname-workspaces.py b/contrib/autoname-workspaces.py index 297d91b2..3ec39928 100755 --- a/contrib/autoname-workspaces.py +++ b/contrib/autoname-workspaces.py | |||
@@ -22,24 +22,17 @@ DEFAULT_ICON = "ó°€" | |||
22 | 22 | ||
23 | 23 | ||
24 | def icon_for_window(window): | 24 | def icon_for_window(window): |
25 | app_id = window.app_id | 25 | name = None |
26 | if app_id is not None and len(app_id) > 0: | 26 | if window.app_id is not None and len(window.app_id) > 0: |
27 | app_id = app_id.lower() | 27 | name = window.app_id.lower() |
28 | if app_id in WINDOW_ICONS: | 28 | elif window.window_class is not None and len(window.window_class) > 0: |
29 | return WINDOW_ICONS[app_id] | 29 | name = window.window_class.lower() |
30 | logging.info("No icon available for window with app_id: %s" % str(app_id)) | 30 | |
31 | else: | 31 | if name in WINDOW_ICONS: |
32 | # xwayland support | 32 | return WINDOW_ICONS[name] |
33 | class_name = window.window_class | ||
34 | if len(class_name) > 0: | ||
35 | class_name = class_name.lower() | ||
36 | if class_name in WINDOW_ICONS: | ||
37 | return WINDOW_ICONS[class_name] | ||
38 | logging.info( | ||
39 | "No icon available for window with class_name: %s" % str(class_name) | ||
40 | ) | ||
41 | return DEFAULT_ICON | ||
42 | 33 | ||
34 | logging.info("No icon available for window with name: %s" % str(name)) | ||
35 | return DEFAULT_ICON | ||
43 | 36 | ||
44 | def rename_workspaces(ipc): | 37 | def rename_workspaces(ipc): |
45 | for workspace in ipc.get_tree().workspaces(): | 38 | for workspace in ipc.get_tree().workspaces(): |
@@ -128,3 +121,4 @@ if __name__ == "__main__": | |||
128 | rename_workspaces(ipc) | 121 | rename_workspaces(ipc) |
129 | 122 | ||
130 | ipc.main() | 123 | ipc.main() |
124 | |||
diff --git a/contrib/grimshot b/contrib/grimshot index 461a5eef..4ce31f29 100755 --- a/contrib/grimshot +++ b/contrib/grimshot | |||
@@ -32,13 +32,13 @@ FILE=${3:-$(getTargetDirectory)/$(date -Ins).png} | |||
32 | 32 | ||
33 | if [ "$ACTION" != "save" ] && [ "$ACTION" != "copy" ] && [ "$ACTION" != "check" ]; then | 33 | if [ "$ACTION" != "save" ] && [ "$ACTION" != "copy" ] && [ "$ACTION" != "check" ]; then |
34 | echo "Usage:" | 34 | echo "Usage:" |
35 | echo " grimshot [--notify] (copy|save) [active|screen|output|area|window] [FILE]" | 35 | echo " grimshot [--notify] (copy|save) [active|screen|output|area|window] [FILE|-]" |
36 | echo " grimshot check" | 36 | echo " grimshot check" |
37 | echo " grimshot usage" | 37 | echo " grimshot usage" |
38 | echo "" | 38 | echo "" |
39 | echo "Commands:" | 39 | echo "Commands:" |
40 | echo " copy: Copy the screenshot data into the clipboard." | 40 | echo " copy: Copy the screenshot data into the clipboard." |
41 | echo " save: Save the screenshot to a regular file." | 41 | echo " save: Save the screenshot to a regular file or '-' to pipe to STDOUT." |
42 | echo " check: Verify if required tools are installed and exit." | 42 | echo " check: Verify if required tools are installed and exit." |
43 | echo " usage: Show this message and exit." | 43 | echo " usage: Show this message and exit." |
44 | echo "" | 44 | echo "" |
@@ -113,7 +113,7 @@ elif [ "$SUBJECT" = "area" ] ; then | |||
113 | GEOM=$(slurp -d) | 113 | GEOM=$(slurp -d) |
114 | # Check if user exited slurp without selecting the area | 114 | # Check if user exited slurp without selecting the area |
115 | if [ -z "$GEOM" ]; then | 115 | if [ -z "$GEOM" ]; then |
116 | exit | 116 | exit 1 |
117 | fi | 117 | fi |
118 | WHAT="Area" | 118 | WHAT="Area" |
119 | elif [ "$SUBJECT" = "active" ] ; then | 119 | elif [ "$SUBJECT" = "active" ] ; then |
@@ -132,7 +132,7 @@ elif [ "$SUBJECT" = "window" ] ; then | |||
132 | GEOM=$(swaymsg -t get_tree | jq -r '.. | select(.pid? and .visible?) | .rect | "\(.x),\(.y) \(.width)x\(.height)"' | slurp) | 132 | GEOM=$(swaymsg -t get_tree | jq -r '.. | select(.pid? and .visible?) | .rect | "\(.x),\(.y) \(.width)x\(.height)"' | slurp) |
133 | # Check if user exited slurp without selecting the area | 133 | # Check if user exited slurp without selecting the area |
134 | if [ -z "$GEOM" ]; then | 134 | if [ -z "$GEOM" ]; then |
135 | exit | 135 | exit 1 |
136 | fi | 136 | fi |
137 | WHAT="Window" | 137 | WHAT="Window" |
138 | else | 138 | else |
diff --git a/contrib/grimshot.1 b/contrib/grimshot.1 index f6c8a377..e4baccfd 100644 --- a/contrib/grimshot.1 +++ b/contrib/grimshot.1 | |||
@@ -5,7 +5,7 @@ | |||
5 | .nh | 5 | .nh |
6 | .ad l | 6 | .ad l |
7 | .\" Begin generated content: | 7 | .\" Begin generated content: |
8 | .TH "grimshot" "1" "2020-12-20" | 8 | .TH "grimshot" "1" "2021-02-23" |
9 | .P | 9 | .P |
10 | .SH NAME | 10 | .SH NAME |
11 | .P | 11 | .P |
@@ -31,6 +31,7 @@ Show notifications to the user that a screenshot has been taken.\& | |||
31 | Save the screenshot into a regular file.\& Grimshot will write images | 31 | Save the screenshot into a regular file.\& Grimshot will write images |
32 | files to \fBXDG_SCREENSHOTS_DIR\fR if this is set (or defined | 32 | files to \fBXDG_SCREENSHOTS_DIR\fR if this is set (or defined |
33 | in \fBuser-dirs.\&dir\fR), or otherwise fall back to \fBXDG_PICTURES_DIR\fR.\& | 33 | in \fBuser-dirs.\&dir\fR), or otherwise fall back to \fBXDG_PICTURES_DIR\fR.\& |
34 | Set FILE to '-' to pipe the output to STDOUT.\& | ||
34 | .P | 35 | .P |
35 | .RE | 36 | .RE |
36 | \fBcopy\fR | 37 | \fBcopy\fR |
diff --git a/contrib/grimshot.1.scd b/contrib/grimshot.1.scd index 4ab58532..d2a57759 100644 --- a/contrib/grimshot.1.scd +++ b/contrib/grimshot.1.scd | |||
@@ -19,6 +19,7 @@ grimshot - a helper for screenshots within sway | |||
19 | Save the screenshot into a regular file. Grimshot will write images | 19 | Save the screenshot into a regular file. Grimshot will write images |
20 | files to *XDG_SCREENSHOTS_DIR* if this is set (or defined | 20 | files to *XDG_SCREENSHOTS_DIR* if this is set (or defined |
21 | in *user-dirs.dir*), or otherwise fall back to *XDG_PICTURES_DIR*. | 21 | in *user-dirs.dir*), or otherwise fall back to *XDG_PICTURES_DIR*. |
22 | Set FILE to '-' to pipe the output to STDOUT. | ||
22 | 23 | ||
23 | *copy* | 24 | *copy* |
24 | Copy the screenshot data (as image/png) into the clipboard. | 25 | Copy the screenshot data (as image/png) into the clipboard. |
diff --git a/contrib/inactive-windows-transparency.py b/contrib/inactive-windows-transparency.py index 77b1f221..b81134dd 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): | |||
15 | global prev_focused | 15 | global prev_focused |
16 | global prev_workspace | 16 | global prev_workspace |
17 | 17 | ||
18 | focused_workspace = ipc.get_tree().find_focused() | ||
19 | |||
20 | if focused_workspace == None: | ||
21 | return | ||
22 | |||
18 | focused = event.container | 23 | focused = event.container |
19 | workspace = ipc.get_tree().find_focused().workspace().num | 24 | workspace = focused_workspace.workspace().num |
20 | 25 | ||
21 | if focused.id != prev_focused.id: # https://github.com/swaywm/sway/issues/2859 | 26 | if focused.id != prev_focused.id: # https://github.com/swaywm/sway/issues/2859 |
22 | focused.command("opacity 1") | 27 | focused.command("opacity 1") |
diff --git a/include/background-image.h b/include/background-image.h index 15935ffd..a97ef375 100644 --- a/include/background-image.h +++ b/include/background-image.h | |||
@@ -1,6 +1,6 @@ | |||
1 | #ifndef _SWAY_BACKGROUND_IMAGE_H | 1 | #ifndef _SWAY_BACKGROUND_IMAGE_H |
2 | #define _SWAY_BACKGROUND_IMAGE_H | 2 | #define _SWAY_BACKGROUND_IMAGE_H |
3 | #include "cairo.h" | 3 | #include "cairo_util.h" |
4 | 4 | ||
5 | enum background_mode { | 5 | enum background_mode { |
6 | BACKGROUND_MODE_STRETCH, | 6 | BACKGROUND_MODE_STRETCH, |
diff --git a/include/cairo.h b/include/cairo_util.h index c1275db2..dc049c6d 100644 --- a/include/cairo.h +++ b/include/cairo_util.h | |||
@@ -1,8 +1,8 @@ | |||
1 | #ifndef _SWAY_CAIRO_H | 1 | #ifndef _SWAY_CAIRO_UTIL_H |
2 | #define _SWAY_CAIRO_H | 2 | #define _SWAY_CAIRO_UTIL_H |
3 | #include "config.h" | 3 | #include "config.h" |
4 | #include <stdint.h> | 4 | #include <stdint.h> |
5 | #include <cairo/cairo.h> | 5 | #include <cairo.h> |
6 | #include <wayland-client-protocol.h> | 6 | #include <wayland-client-protocol.h> |
7 | 7 | ||
8 | void cairo_set_source_u32(cairo_t *cairo, uint32_t color); | 8 | void cairo_set_source_u32(cairo_t *cairo, uint32_t color); |
diff --git a/include/pango.h b/include/pango.h index 6ab83c16..93affc23 100644 --- a/include/pango.h +++ b/include/pango.h | |||
@@ -3,7 +3,7 @@ | |||
3 | #include <stdarg.h> | 3 | #include <stdarg.h> |
4 | #include <stdbool.h> | 4 | #include <stdbool.h> |
5 | #include <stdint.h> | 5 | #include <stdint.h> |
6 | #include <cairo/cairo.h> | 6 | #include <cairo.h> |
7 | #include <pango/pangocairo.h> | 7 | #include <pango/pangocairo.h> |
8 | 8 | ||
9 | /** | 9 | /** |
@@ -17,7 +17,8 @@ PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, | |||
17 | const char *text, double scale, bool markup); | 17 | const char *text, double scale, bool markup); |
18 | void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, | 18 | void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, |
19 | int *baseline, double scale, bool markup, const char *fmt, ...); | 19 | int *baseline, double scale, bool markup, const char *fmt, ...); |
20 | void pango_printf(cairo_t *cairo, const char *font, | 20 | void get_text_metrics(const char *font, int *height, int *baseline); |
21 | void render_text(cairo_t *cairo, const char *font, | ||
21 | double scale, bool markup, const char *fmt, ...); | 22 | double scale, bool markup, const char *fmt, ...); |
22 | 23 | ||
23 | #endif | 24 | #endif |
diff --git a/include/pool-buffer.h b/include/pool-buffer.h index 54f5be06..b7a95afe 100644 --- a/include/pool-buffer.h +++ b/include/pool-buffer.h | |||
@@ -1,6 +1,6 @@ | |||
1 | #ifndef _SWAY_BUFFERS_H | 1 | #ifndef _SWAY_BUFFERS_H |
2 | #define _SWAY_BUFFERS_H | 2 | #define _SWAY_BUFFERS_H |
3 | #include <cairo/cairo.h> | 3 | #include <cairo.h> |
4 | #include <pango/pangocairo.h> | 4 | #include <pango/pangocairo.h> |
5 | #include <stdbool.h> | 5 | #include <stdbool.h> |
6 | #include <stdint.h> | 6 | #include <stdint.h> |
diff --git a/include/sway/commands.h b/include/sway/commands.h index 964b3661..4be40870 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h | |||
@@ -46,8 +46,8 @@ enum expected_args { | |||
46 | struct cmd_results *checkarg(int argc, const char *name, | 46 | struct cmd_results *checkarg(int argc, const char *name, |
47 | enum expected_args type, int val); | 47 | enum expected_args type, int val); |
48 | 48 | ||
49 | struct cmd_handler *find_handler(char *line, struct cmd_handler *cmd_handlers, | 49 | const struct cmd_handler *find_handler(char *line, |
50 | size_t handlers_size); | 50 | const struct cmd_handler *cmd_handlers, size_t handlers_size); |
51 | 51 | ||
52 | /** | 52 | /** |
53 | * Parse and executes a command. | 53 | * Parse and executes a command. |
@@ -68,7 +68,7 @@ struct cmd_results *config_command(char *command, char **new_block); | |||
68 | * Parse and handle a sub command | 68 | * Parse and handle a sub command |
69 | */ | 69 | */ |
70 | struct cmd_results *config_subcommand(char **argv, int argc, | 70 | struct cmd_results *config_subcommand(char **argv, int argc, |
71 | struct cmd_handler *handlers, size_t handlers_size); | 71 | const struct cmd_handler *handlers, size_t handlers_size); |
72 | /* | 72 | /* |
73 | * Parses a command policy rule. | 73 | * Parses a command policy rule. |
74 | */ | 74 | */ |
@@ -282,6 +282,7 @@ sway_cmd output_cmd_dpms; | |||
282 | sway_cmd output_cmd_enable; | 282 | sway_cmd output_cmd_enable; |
283 | sway_cmd output_cmd_max_render_time; | 283 | sway_cmd output_cmd_max_render_time; |
284 | sway_cmd output_cmd_mode; | 284 | sway_cmd output_cmd_mode; |
285 | sway_cmd output_cmd_modeline; | ||
285 | sway_cmd output_cmd_position; | 286 | sway_cmd output_cmd_position; |
286 | sway_cmd output_cmd_scale; | 287 | sway_cmd output_cmd_scale; |
287 | sway_cmd output_cmd_scale_filter; | 288 | sway_cmd output_cmd_scale_filter; |
diff --git a/include/sway/config.h b/include/sway/config.h index 59f22ae2..46dd4ffe 100644 --- a/include/sway/config.h +++ b/include/sway/config.h | |||
@@ -5,9 +5,10 @@ | |||
5 | #include <string.h> | 5 | #include <string.h> |
6 | #include <time.h> | 6 | #include <time.h> |
7 | #include <wlr/interfaces/wlr_switch.h> | 7 | #include <wlr/interfaces/wlr_switch.h> |
8 | #include <wlr/types/wlr_box.h> | ||
9 | #include <wlr/types/wlr_tablet_tool.h> | 8 | #include <wlr/types/wlr_tablet_tool.h> |
9 | #include <wlr/util/box.h> | ||
10 | #include <xkbcommon/xkbcommon.h> | 10 | #include <xkbcommon/xkbcommon.h> |
11 | #include <xf86drmMode.h> | ||
11 | #include "../include/config.h" | 12 | #include "../include/config.h" |
12 | #include "list.h" | 13 | #include "list.h" |
13 | #include "swaynag.h" | 14 | #include "swaynag.h" |
@@ -257,6 +258,7 @@ struct output_config { | |||
257 | int width, height; | 258 | int width, height; |
258 | float refresh_rate; | 259 | float refresh_rate; |
259 | int custom_mode; | 260 | int custom_mode; |
261 | drmModeModeInfo drm_mode; | ||
260 | int x, y; | 262 | int x, y; |
261 | float scale; | 263 | float scale; |
262 | enum scale_filter_mode scale_filter; | 264 | enum scale_filter_mode scale_filter; |
@@ -292,6 +294,12 @@ struct workspace_config { | |||
292 | struct side_gaps gaps_outer; | 294 | struct side_gaps gaps_outer; |
293 | }; | 295 | }; |
294 | 296 | ||
297 | enum pango_markup_config { | ||
298 | PANGO_MARKUP_DISABLED = false, | ||
299 | PANGO_MARKUP_ENABLED = true, | ||
300 | PANGO_MARKUP_DEFAULT // The default is font dependent ("pango:" prefix) | ||
301 | }; | ||
302 | |||
295 | struct bar_config { | 303 | struct bar_config { |
296 | char *swaybar_command; | 304 | char *swaybar_command; |
297 | struct wl_client *client; | 305 | struct wl_client *client; |
@@ -323,7 +331,7 @@ struct bar_config { | |||
323 | char *position; | 331 | char *position; |
324 | list_t *bindings; | 332 | list_t *bindings; |
325 | char *status_command; | 333 | char *status_command; |
326 | bool pango_markup; | 334 | enum pango_markup_config pango_markup; |
327 | char *font; | 335 | char *font; |
328 | int height; // -1 not defined | 336 | int height; // -1 not defined |
329 | bool workspace_buttons; | 337 | bool workspace_buttons; |
@@ -410,14 +418,6 @@ enum sway_popup_during_fullscreen { | |||
410 | POPUP_LEAVE, | 418 | POPUP_LEAVE, |
411 | }; | 419 | }; |
412 | 420 | ||
413 | enum command_context { | ||
414 | CONTEXT_CONFIG = 1 << 0, | ||
415 | CONTEXT_BINDING = 1 << 1, | ||
416 | CONTEXT_IPC = 1 << 2, | ||
417 | CONTEXT_CRITERIA = 1 << 3, | ||
418 | CONTEXT_ALL = 0xFFFFFFFF, | ||
419 | }; | ||
420 | |||
421 | enum focus_follows_mouse_mode { | 421 | enum focus_follows_mouse_mode { |
422 | FOLLOWS_NO, | 422 | FOLLOWS_NO, |
423 | FOLLOWS_YES, | 423 | FOLLOWS_YES, |
@@ -480,8 +480,8 @@ struct sway_config { | |||
480 | enum sway_container_layout default_orientation; | 480 | enum sway_container_layout default_orientation; |
481 | enum sway_container_layout default_layout; | 481 | enum sway_container_layout default_layout; |
482 | char *font; | 482 | char *font; |
483 | size_t font_height; | 483 | int font_height; |
484 | size_t font_baseline; | 484 | int font_baseline; |
485 | bool pango_markup; | 485 | bool pango_markup; |
486 | int titlebar_border_thickness; | 486 | int titlebar_border_thickness; |
487 | int titlebar_h_padding; | 487 | int titlebar_h_padding; |
@@ -559,7 +559,7 @@ struct sway_config { | |||
559 | struct sway_node *node; | 559 | struct sway_node *node; |
560 | struct sway_container *container; | 560 | struct sway_container *container; |
561 | struct sway_workspace *workspace; | 561 | struct sway_workspace *workspace; |
562 | bool using_criteria; | 562 | bool node_overridden; // True if the node is selected by means other than focus |
563 | struct { | 563 | struct { |
564 | int argc; | 564 | int argc; |
565 | char **argv; | 565 | char **argv; |
@@ -690,14 +690,13 @@ void free_bar_binding(struct bar_binding *binding); | |||
690 | void free_workspace_config(struct workspace_config *wsc); | 690 | void free_workspace_config(struct workspace_config *wsc); |
691 | 691 | ||
692 | /** | 692 | /** |
693 | * Updates the value of config->font_height based on the max title height | 693 | * Updates the value of config->font_height based on the metrics for title's |
694 | * reported by each container. If recalculate is true, the containers will | 694 | * font as reported by pango. |
695 | * recalculate their heights before reporting. | 695 | * |
696 | * | ||
697 | * If the height has changed, all containers will be rearranged to take on the | 696 | * If the height has changed, all containers will be rearranged to take on the |
698 | * new size. | 697 | * new size. |
699 | */ | 698 | */ |
700 | void config_update_font_height(bool recalculate); | 699 | void config_update_font_height(void); |
701 | 700 | ||
702 | /** | 701 | /** |
703 | * Convert bindsym into bindcode using the first configured layout. | 702 | * 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 0adafdb9..58d54c68 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 { | |||
22 | 22 | ||
23 | struct sway_idle_inhibitor_v1 { | 23 | struct sway_idle_inhibitor_v1 { |
24 | struct sway_idle_inhibit_manager_v1 *manager; | 24 | struct sway_idle_inhibit_manager_v1 *manager; |
25 | struct wlr_idle_inhibitor_v1 *wlr_inhibitor; | ||
25 | struct sway_view *view; | 26 | struct sway_view *view; |
26 | enum sway_idle_inhibit_mode mode; | 27 | enum sway_idle_inhibit_mode mode; |
27 | 28 | ||
diff --git a/include/sway/desktop/transaction.h b/include/sway/desktop/transaction.h index 175489c5..7dd58ba8 100644 --- a/include/sway/desktop/transaction.h +++ b/include/sway/desktop/transaction.h | |||
@@ -28,6 +28,12 @@ struct sway_view; | |||
28 | */ | 28 | */ |
29 | void transaction_commit_dirty(void); | 29 | void transaction_commit_dirty(void); |
30 | 30 | ||
31 | /* | ||
32 | * Same as transaction_commit_dirty, but signalling that this is a | ||
33 | * client-initiated change has already taken effect. | ||
34 | */ | ||
35 | void transaction_commit_dirty_client(void); | ||
36 | |||
31 | /** | 37 | /** |
32 | * Notify the transaction system that a view is ready for the new layout. | 38 | * Notify the transaction system that a view is ready for the new layout. |
33 | * | 39 | * |
@@ -45,10 +51,4 @@ void transaction_notify_view_ready_by_serial(struct sway_view *view, | |||
45 | void transaction_notify_view_ready_by_geometry(struct sway_view *view, | 51 | void transaction_notify_view_ready_by_geometry(struct sway_view *view, |
46 | double x, double y, int width, int height); | 52 | double x, double y, int width, int height); |
47 | 53 | ||
48 | /** | ||
49 | * Unconditionally notify the transaction system that a view is ready for the | ||
50 | * new layout. | ||
51 | */ | ||
52 | void transaction_notify_view_ready_immediately(struct sway_view *view); | ||
53 | |||
54 | #endif | 54 | #endif |
diff --git a/include/sway/input/cursor.h b/include/sway/input/cursor.h index 6a38190b..7d66e699 100644 --- a/include/sway/input/cursor.h +++ b/include/sway/input/cursor.h | |||
@@ -52,7 +52,9 @@ struct sway_cursor { | |||
52 | struct wl_listener touch_down; | 52 | struct wl_listener touch_down; |
53 | struct wl_listener touch_up; | 53 | struct wl_listener touch_up; |
54 | struct wl_listener touch_motion; | 54 | struct wl_listener touch_motion; |
55 | struct wl_listener touch_frame; | ||
55 | bool simulating_pointer_from_touch; | 56 | bool simulating_pointer_from_touch; |
57 | bool pointer_touch_up; | ||
56 | int32_t pointer_touch_id; | 58 | int32_t pointer_touch_id; |
57 | 59 | ||
58 | struct wl_listener tool_axis; | 60 | struct wl_listener tool_axis; |
diff --git a/include/sway/input/libinput.h b/include/sway/input/libinput.h index de019976..890d632e 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); | |||
6 | 6 | ||
7 | void sway_input_reset_libinput_device(struct sway_input_device *device); | 7 | void sway_input_reset_libinput_device(struct sway_input_device *device); |
8 | 8 | ||
9 | bool sway_libinput_device_is_builtin(struct sway_input_device *device); | ||
10 | |||
9 | #endif | 11 | #endif |
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index 4118df66..77c2278d 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h | |||
@@ -239,7 +239,10 @@ enum wlr_edges find_resize_edge(struct sway_container *cont, | |||
239 | void seatop_begin_default(struct sway_seat *seat); | 239 | void seatop_begin_default(struct sway_seat *seat); |
240 | 240 | ||
241 | void seatop_begin_down(struct sway_seat *seat, struct sway_container *con, | 241 | void seatop_begin_down(struct sway_seat *seat, struct sway_container *con, |
242 | uint32_t time_msec, int sx, int sy); | 242 | uint32_t time_msec, double sx, double sy); |
243 | |||
244 | void seatop_begin_down_on_surface(struct sway_seat *seat, | ||
245 | struct wlr_surface *surface, uint32_t time_msec, double sx, double sy); | ||
243 | 246 | ||
244 | void seatop_begin_move_floating(struct sway_seat *seat, | 247 | void seatop_begin_move_floating(struct sway_seat *seat, |
245 | struct sway_container *con); | 248 | struct sway_container *con); |
diff --git a/include/sway/input/text_input.h b/include/sway/input/text_input.h index 6cf9bdb3..37744266 100644 --- a/include/sway/input/text_input.h +++ b/include/sway/input/text_input.h | |||
@@ -28,7 +28,10 @@ struct sway_input_method_relay { | |||
28 | 28 | ||
29 | struct wl_listener input_method_new; | 29 | struct wl_listener input_method_new; |
30 | struct wl_listener input_method_commit; | 30 | struct wl_listener input_method_commit; |
31 | struct wl_listener input_method_grab_keyboard; | ||
31 | struct wl_listener input_method_destroy; | 32 | struct wl_listener input_method_destroy; |
33 | |||
34 | struct wl_listener input_method_keyboard_grab_destroy; | ||
32 | }; | 35 | }; |
33 | 36 | ||
34 | struct sway_text_input { | 37 | struct sway_text_input { |
diff --git a/include/sway/layers.h b/include/sway/layers.h index 457634c2..224dc5e6 100644 --- a/include/sway/layers.h +++ b/include/sway/layers.h | |||
@@ -1,7 +1,6 @@ | |||
1 | #ifndef _SWAY_LAYERS_H | 1 | #ifndef _SWAY_LAYERS_H |
2 | #define _SWAY_LAYERS_H | 2 | #define _SWAY_LAYERS_H |
3 | #include <stdbool.h> | 3 | #include <stdbool.h> |
4 | #include <wlr/types/wlr_box.h> | ||
5 | #include <wlr/types/wlr_surface.h> | 4 | #include <wlr/types/wlr_surface.h> |
6 | #include <wlr/types/wlr_layer_shell_v1.h> | 5 | #include <wlr/types/wlr_layer_shell_v1.h> |
7 | 6 | ||
@@ -23,6 +22,8 @@ struct sway_layer_surface { | |||
23 | struct wl_listener new_subsurface; | 22 | struct wl_listener new_subsurface; |
24 | 23 | ||
25 | struct wlr_box geo; | 24 | struct wlr_box geo; |
25 | bool mapped; | ||
26 | struct wlr_box extent; | ||
26 | enum zwlr_layer_shell_v1_layer layer; | 27 | enum zwlr_layer_shell_v1_layer layer; |
27 | }; | 28 | }; |
28 | 29 | ||
diff --git a/include/sway/output.h b/include/sway/output.h index 96986700..5dfe0fff 100644 --- a/include/sway/output.h +++ b/include/sway/output.h | |||
@@ -3,7 +3,6 @@ | |||
3 | #include <time.h> | 3 | #include <time.h> |
4 | #include <unistd.h> | 4 | #include <unistd.h> |
5 | #include <wayland-server-core.h> | 5 | #include <wayland-server-core.h> |
6 | #include <wlr/types/wlr_box.h> | ||
7 | #include <wlr/types/wlr_output.h> | 6 | #include <wlr/types/wlr_output.h> |
8 | #include "config.h" | 7 | #include "config.h" |
9 | #include "sway/tree/node.h" | 8 | #include "sway/tree/node.h" |
@@ -72,8 +71,8 @@ struct sway_output *output_get_in_direction(struct sway_output *reference, | |||
72 | void output_add_workspace(struct sway_output *output, | 71 | void output_add_workspace(struct sway_output *output, |
73 | struct sway_workspace *workspace); | 72 | struct sway_workspace *workspace); |
74 | 73 | ||
75 | typedef void (*sway_surface_iterator_func_t)(struct sway_output *output, struct sway_view *view, | 74 | typedef void (*sway_surface_iterator_func_t)(struct sway_output *output, |
76 | struct wlr_surface *surface, struct wlr_box *box, float rotation, | 75 | struct sway_view *view, struct wlr_surface *surface, struct wlr_box *box, |
77 | void *user_data); | 76 | void *user_data); |
78 | 77 | ||
79 | void output_damage_whole(struct sway_output *output); | 78 | void output_damage_whole(struct sway_output *output); |
diff --git a/include/sway/server.h b/include/sway/server.h index 0f5e3ab2..88dda097 100644 --- a/include/sway/server.h +++ b/include/sway/server.h | |||
@@ -9,6 +9,7 @@ | |||
9 | #include <wlr/types/wlr_data_device.h> | 9 | #include <wlr/types/wlr_data_device.h> |
10 | #include <wlr/types/wlr_input_method_v2.h> | 10 | #include <wlr/types/wlr_input_method_v2.h> |
11 | #include <wlr/types/wlr_foreign_toplevel_management_v1.h> | 11 | #include <wlr/types/wlr_foreign_toplevel_management_v1.h> |
12 | #include <wlr/types/wlr_drm_lease_v1.h> | ||
12 | #include <wlr/types/wlr_layer_shell_v1.h> | 13 | #include <wlr/types/wlr_layer_shell_v1.h> |
13 | #include <wlr/types/wlr_output_management_v1.h> | 14 | #include <wlr/types/wlr_output_management_v1.h> |
14 | #include <wlr/types/wlr_output_power_management_v1.h> | 15 | #include <wlr/types/wlr_output_power_management_v1.h> |
@@ -23,6 +24,8 @@ | |||
23 | #include "sway/xwayland.h" | 24 | #include "sway/xwayland.h" |
24 | #endif | 25 | #endif |
25 | 26 | ||
27 | struct sway_transaction; | ||
28 | |||
26 | struct sway_server { | 29 | struct sway_server { |
27 | struct wl_display *wl_display; | 30 | struct wl_display *wl_display; |
28 | struct wl_event_loop *wl_event_loop; | 31 | struct wl_event_loop *wl_event_loop; |
@@ -70,6 +73,9 @@ struct sway_server { | |||
70 | struct wl_listener xdg_decoration; | 73 | struct wl_listener xdg_decoration; |
71 | struct wl_list xdg_decorations; // sway_xdg_decoration::link | 74 | struct wl_list xdg_decorations; // sway_xdg_decoration::link |
72 | 75 | ||
76 | struct wlr_drm_lease_v1_manager *drm_lease_manager; | ||
77 | struct wl_listener drm_lease_request; | ||
78 | |||
73 | struct wlr_presentation *presentation; | 79 | struct wlr_presentation *presentation; |
74 | 80 | ||
75 | struct wlr_pointer_constraints_v1 *pointer_constraints; | 81 | struct wlr_pointer_constraints_v1 *pointer_constraints; |
@@ -85,8 +91,25 @@ struct sway_server { | |||
85 | struct wlr_text_input_manager_v3 *text_input; | 91 | struct wlr_text_input_manager_v3 *text_input; |
86 | struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager; | 92 | struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager; |
87 | 93 | ||
94 | struct wlr_xdg_activation_v1 *xdg_activation_v1; | ||
95 | struct wl_listener xdg_activation_v1_request_activate; | ||
96 | |||
97 | // The timeout for transactions, after which a transaction is applied | ||
98 | // regardless of readiness. | ||
88 | size_t txn_timeout_ms; | 99 | size_t txn_timeout_ms; |
89 | list_t *transactions; | 100 | |
101 | // Stores a transaction after it has been committed, but is waiting for | ||
102 | // views to ack the new dimensions before being applied. A queued | ||
103 | // transaction is frozen and must not have new instructions added to it. | ||
104 | struct sway_transaction *queued_transaction; | ||
105 | |||
106 | // Stores a pending transaction that will be committed once the existing | ||
107 | // queued transaction is applied and freed. The pending transaction can be | ||
108 | // updated with new instructions as needed. | ||
109 | struct sway_transaction *pending_transaction; | ||
110 | |||
111 | // Stores the nodes that have been marked as "dirty" and will be put into | ||
112 | // the pending transaction. | ||
90 | list_t *dirty_nodes; | 113 | list_t *dirty_nodes; |
91 | }; | 114 | }; |
92 | 115 | ||
@@ -96,6 +119,7 @@ struct sway_debug { | |||
96 | bool noatomic; // Ignore atomic layout updates | 119 | bool noatomic; // Ignore atomic layout updates |
97 | bool txn_timings; // Log verbose messages about transactions | 120 | bool txn_timings; // Log verbose messages about transactions |
98 | bool txn_wait; // Always wait for the timeout before applying | 121 | bool txn_wait; // Always wait for the timeout before applying |
122 | bool noscanout; // Disable direct scan-out | ||
99 | 123 | ||
100 | enum { | 124 | enum { |
101 | DAMAGE_DEFAULT, // Default behaviour | 125 | DAMAGE_DEFAULT, // Default behaviour |
@@ -125,5 +149,7 @@ void handle_xwayland_surface(struct wl_listener *listener, void *data); | |||
125 | void handle_server_decoration(struct wl_listener *listener, void *data); | 149 | void handle_server_decoration(struct wl_listener *listener, void *data); |
126 | void handle_xdg_decoration(struct wl_listener *listener, void *data); | 150 | void handle_xdg_decoration(struct wl_listener *listener, void *data); |
127 | void handle_pointer_constraint(struct wl_listener *listener, void *data); | 151 | void handle_pointer_constraint(struct wl_listener *listener, void *data); |
152 | void xdg_activation_v1_handle_request_activate(struct wl_listener *listener, | ||
153 | void *data); | ||
128 | 154 | ||
129 | #endif | 155 | #endif |
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h index 7e9df59f..97fa98c1 100644 --- a/include/sway/tree/container.h +++ b/include/sway/tree/container.h | |||
@@ -2,7 +2,6 @@ | |||
2 | #define _SWAY_CONTAINER_H | 2 | #define _SWAY_CONTAINER_H |
3 | #include <stdint.h> | 3 | #include <stdint.h> |
4 | #include <sys/types.h> | 4 | #include <sys/types.h> |
5 | #include <wlr/types/wlr_box.h> | ||
6 | #include <wlr/types/wlr_surface.h> | 5 | #include <wlr/types/wlr_surface.h> |
7 | #include "list.h" | 6 | #include "list.h" |
8 | #include "sway/tree/node.h" | 7 | #include "sway/tree/node.h" |
@@ -46,9 +45,9 @@ struct sway_container_state { | |||
46 | 45 | ||
47 | enum sway_fullscreen_mode fullscreen_mode; | 46 | enum sway_fullscreen_mode fullscreen_mode; |
48 | 47 | ||
49 | struct sway_workspace *workspace; | 48 | struct sway_workspace *workspace; // NULL when hidden in the scratchpad |
50 | struct sway_container *parent; | 49 | struct sway_container *parent; // NULL if container in root of workspace |
51 | list_t *children; | 50 | list_t *children; // struct sway_container |
52 | 51 | ||
53 | struct sway_container *focused_inactive_child; | 52 | struct sway_container *focused_inactive_child; |
54 | bool focused; | 53 | bool focused; |
@@ -60,6 +59,7 @@ struct sway_container_state { | |||
60 | bool border_left; | 59 | bool border_left; |
61 | bool border_right; | 60 | bool border_right; |
62 | 61 | ||
62 | // These are in layout coordinates. | ||
63 | double content_x, content_y; | 63 | double content_x, content_y; |
64 | double content_width, content_height; | 64 | double content_width, content_height; |
65 | }; | 65 | }; |
@@ -68,14 +68,12 @@ struct sway_container { | |||
68 | struct sway_node node; | 68 | struct sway_node node; |
69 | struct sway_view *view; | 69 | struct sway_view *view; |
70 | 70 | ||
71 | // The pending state is the main container properties, and the current state is in the below struct. | ||
72 | // This means most places of the code can refer to the main variables (pending state) and it'll just work. | ||
73 | struct sway_container_state current; | 71 | struct sway_container_state current; |
72 | struct sway_container_state pending; | ||
74 | 73 | ||
75 | char *title; // The view's title (unformatted) | 74 | char *title; // The view's title (unformatted) |
76 | char *formatted_title; // The title displayed in the title bar | 75 | char *formatted_title; // The title displayed in the title bar |
77 | 76 | ||
78 | enum sway_container_layout layout; | ||
79 | enum sway_container_layout prev_split_layout; | 77 | enum sway_container_layout prev_split_layout; |
80 | 78 | ||
81 | // Whether stickiness has been enabled on this container. Use | 79 | // Whether stickiness has been enabled on this container. Use |
@@ -86,11 +84,13 @@ struct sway_container { | |||
86 | // For C_ROOT, this has no meaning | 84 | // For C_ROOT, this has no meaning |
87 | // For other types, this is the position in layout coordinates | 85 | // For other types, this is the position in layout coordinates |
88 | // Includes borders | 86 | // Includes borders |
89 | double x, y; | ||
90 | double width, height; | ||
91 | double saved_x, saved_y; | 87 | double saved_x, saved_y; |
92 | double saved_width, saved_height; | 88 | double saved_width, saved_height; |
93 | 89 | ||
90 | // Used when the view changes to CSD unexpectedly. This will be a non-B_CSD | ||
91 | // border which we use to restore when the view returns to SSD. | ||
92 | enum sway_container_border saved_border; | ||
93 | |||
94 | // The share of the space of parent container this container occupies | 94 | // The share of the space of parent container this container occupies |
95 | double width_fraction; | 95 | double width_fraction; |
96 | double height_fraction; | 96 | double height_fraction; |
@@ -100,33 +100,11 @@ struct sway_container { | |||
100 | double child_total_width; | 100 | double child_total_width; |
101 | double child_total_height; | 101 | double child_total_height; |
102 | 102 | ||
103 | // These are in layout coordinates. | ||
104 | double content_x, content_y; | ||
105 | int content_width, content_height; | ||
106 | |||
107 | // In most cases this is the same as the content x and y, but if the view | 103 | // In most cases this is the same as the content x and y, but if the view |
108 | // refuses to resize to the content dimensions then it can be smaller. | 104 | // refuses to resize to the content dimensions then it can be smaller. |
109 | // These are in layout coordinates. | 105 | // These are in layout coordinates. |
110 | double surface_x, surface_y; | 106 | double surface_x, surface_y; |
111 | 107 | ||
112 | enum sway_fullscreen_mode fullscreen_mode; | ||
113 | |||
114 | enum sway_container_border border; | ||
115 | |||
116 | // Used when the view changes to CSD unexpectedly. This will be a non-B_CSD | ||
117 | // border which we use to restore when the view returns to SSD. | ||
118 | enum sway_container_border saved_border; | ||
119 | |||
120 | int border_thickness; | ||
121 | bool border_top; | ||
122 | bool border_bottom; | ||
123 | bool border_left; | ||
124 | bool border_right; | ||
125 | |||
126 | struct sway_workspace *workspace; // NULL when hidden in the scratchpad | ||
127 | struct sway_container *parent; // NULL if container in root of workspace | ||
128 | list_t *children; // struct sway_container | ||
129 | |||
130 | // Outputs currently being intersected | 108 | // Outputs currently being intersected |
131 | list_t *outputs; // struct sway_output | 109 | list_t *outputs; // struct sway_output |
132 | 110 | ||
@@ -141,8 +119,6 @@ struct sway_container { | |||
141 | struct wlr_texture *title_focused_inactive; | 119 | struct wlr_texture *title_focused_inactive; |
142 | struct wlr_texture *title_unfocused; | 120 | struct wlr_texture *title_unfocused; |
143 | struct wlr_texture *title_urgent; | 121 | struct wlr_texture *title_urgent; |
144 | size_t title_height; | ||
145 | size_t title_baseline; | ||
146 | 122 | ||
147 | list_t *marks; // char * | 123 | list_t *marks; // char * |
148 | struct wlr_texture *marks_focused; | 124 | struct wlr_texture *marks_focused; |
@@ -185,6 +161,11 @@ void container_for_each_child(struct sway_container *container, | |||
185 | void (*f)(struct sway_container *container, void *data), void *data); | 161 | void (*f)(struct sway_container *container, void *data), void *data); |
186 | 162 | ||
187 | /** | 163 | /** |
164 | * Returns the fullscreen container obstructing this container if it exists. | ||
165 | */ | ||
166 | struct sway_container *container_obstructing_fullscreen_container(struct sway_container *container); | ||
167 | |||
168 | /** | ||
188 | * Returns true if the given container is an ancestor of this container. | 169 | * Returns true if the given container is an ancestor of this container. |
189 | */ | 170 | */ |
190 | bool container_has_ancestor(struct sway_container *container, | 171 | bool container_has_ancestor(struct sway_container *container, |
@@ -200,11 +181,6 @@ struct sway_container *container_flatten(struct sway_container *container); | |||
200 | 181 | ||
201 | void container_update_title_textures(struct sway_container *container); | 182 | void container_update_title_textures(struct sway_container *container); |
202 | 183 | ||
203 | /** | ||
204 | * Calculate the container's title_height property. | ||
205 | */ | ||
206 | void container_calculate_title_height(struct sway_container *container); | ||
207 | |||
208 | size_t container_build_representation(enum sway_container_layout layout, | 184 | size_t container_build_representation(enum sway_container_layout layout, |
209 | list_t *children, char *buffer); | 185 | list_t *children, char *buffer); |
210 | 186 | ||
@@ -231,10 +207,17 @@ void container_set_geometry_from_content(struct sway_container *con); | |||
231 | /** | 207 | /** |
232 | * Determine if the given container is itself floating. | 208 | * Determine if the given container is itself floating. |
233 | * This will return false for any descendants of a floating container. | 209 | * This will return false for any descendants of a floating container. |
210 | * | ||
211 | * Uses pending container state. | ||
234 | */ | 212 | */ |
235 | bool container_is_floating(struct sway_container *container); | 213 | bool container_is_floating(struct sway_container *container); |
236 | 214 | ||
237 | /** | 215 | /** |
216 | * Same as above, but for current container state. | ||
217 | */ | ||
218 | bool container_is_current_floating(struct sway_container *container); | ||
219 | |||
220 | /** | ||
238 | * Get a container's box in layout coordinates. | 221 | * Get a container's box in layout coordinates. |
239 | */ | 222 | */ |
240 | void container_get_box(struct sway_container *container, struct wlr_box *box); | 223 | void container_get_box(struct sway_container *container, struct wlr_box *box); |
@@ -299,6 +282,7 @@ bool container_is_fullscreen_or_child(struct sway_container *container); | |||
299 | /** | 282 | /** |
300 | * Return the output which will be used for scale purposes. | 283 | * Return the output which will be used for scale purposes. |
301 | * This is the most recently entered output. | 284 | * This is the most recently entered output. |
285 | * If the container is not on any output, return NULL. | ||
302 | */ | 286 | */ |
303 | struct sway_output *container_get_effective_output(struct sway_container *con); | 287 | struct sway_output *container_get_effective_output(struct sway_container *con); |
304 | 288 | ||
diff --git a/include/sway/tree/view.h b/include/sway/tree/view.h index e071e6c9..008361f7 100644 --- a/include/sway/tree/view.h +++ b/include/sway/tree/view.h | |||
@@ -112,7 +112,6 @@ struct sway_view { | |||
112 | #if HAVE_XWAYLAND | 112 | #if HAVE_XWAYLAND |
113 | struct wlr_xwayland_surface *wlr_xwayland_surface; | 113 | struct wlr_xwayland_surface *wlr_xwayland_surface; |
114 | #endif | 114 | #endif |
115 | struct wlr_wl_shell_surface *wlr_wl_shell_surface; | ||
116 | }; | 115 | }; |
117 | 116 | ||
118 | struct { | 117 | struct { |
@@ -132,7 +131,6 @@ struct sway_xdg_shell_view { | |||
132 | struct wl_listener commit; | 131 | struct wl_listener commit; |
133 | struct wl_listener request_move; | 132 | struct wl_listener request_move; |
134 | struct wl_listener request_resize; | 133 | struct wl_listener request_resize; |
135 | struct wl_listener request_maximize; | ||
136 | struct wl_listener request_fullscreen; | 134 | struct wl_listener request_fullscreen; |
137 | struct wl_listener set_title; | 135 | struct wl_listener set_title; |
138 | struct wl_listener set_app_id; | 136 | struct wl_listener set_app_id; |
@@ -184,7 +182,7 @@ struct sway_xwayland_unmanaged { | |||
184 | struct sway_view_child; | 182 | struct sway_view_child; |
185 | 183 | ||
186 | struct sway_view_child_impl { | 184 | struct sway_view_child_impl { |
187 | void (*get_root_coords)(struct sway_view_child *child, int *sx, int *sy); | 185 | void (*get_view_coords)(struct sway_view_child *child, int *sx, int *sy); |
188 | void (*destroy)(struct sway_view_child *child); | 186 | void (*destroy)(struct sway_view_child *child); |
189 | }; | 187 | }; |
190 | 188 | ||
@@ -311,12 +309,22 @@ void view_destroy(struct sway_view *view); | |||
311 | 309 | ||
312 | void view_begin_destroy(struct sway_view *view); | 310 | void view_begin_destroy(struct sway_view *view); |
313 | 311 | ||
312 | /** | ||
313 | * Map a view, ie. make it visible in the tree. | ||
314 | * | ||
315 | * `fullscreen` should be set to true (and optionally `fullscreen_output` | ||
316 | * should be populated) if the view should be made fullscreen immediately. | ||
317 | * | ||
318 | * `decoration` should be set to true if the client prefers CSD. The client's | ||
319 | * preference may be ignored. | ||
320 | */ | ||
314 | void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, | 321 | void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, |
315 | bool fullscreen, struct wlr_output *fullscreen_output, bool decoration); | 322 | bool fullscreen, struct wlr_output *fullscreen_output, bool decoration); |
316 | 323 | ||
317 | void view_unmap(struct sway_view *view); | 324 | void view_unmap(struct sway_view *view); |
318 | 325 | ||
319 | void view_update_size(struct sway_view *view, int width, int height); | 326 | void view_update_size(struct sway_view *view); |
327 | void view_center_surface(struct sway_view *view); | ||
320 | 328 | ||
321 | void view_child_init(struct sway_view_child *child, | 329 | void view_child_init(struct sway_view_child *child, |
322 | const struct sway_view_child_impl *impl, struct sway_view *view, | 330 | 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 fdd92f64..b3d93a81 100644 --- a/include/sway/tree/workspace.h +++ b/include/sway/tree/workspace.h | |||
@@ -60,20 +60,20 @@ void workspace_consider_destroy(struct sway_workspace *ws); | |||
60 | 60 | ||
61 | char *workspace_next_name(const char *output_name); | 61 | char *workspace_next_name(const char *output_name); |
62 | 62 | ||
63 | bool workspace_switch(struct sway_workspace *workspace, | 63 | struct sway_workspace *workspace_auto_back_and_forth( |
64 | bool no_auto_back_and_forth); | 64 | struct sway_workspace *workspace); |
65 | |||
66 | bool workspace_switch(struct sway_workspace *workspace); | ||
65 | 67 | ||
66 | struct sway_workspace *workspace_by_number(const char* name); | 68 | struct sway_workspace *workspace_by_number(const char* name); |
67 | 69 | ||
68 | struct sway_workspace *workspace_by_name(const char*); | 70 | struct sway_workspace *workspace_by_name(const char*); |
69 | 71 | ||
70 | struct sway_workspace *workspace_output_next( | 72 | struct sway_workspace *workspace_output_next(struct sway_workspace *current); |
71 | struct sway_workspace *current, bool create); | ||
72 | 73 | ||
73 | struct sway_workspace *workspace_next(struct sway_workspace *current); | 74 | struct sway_workspace *workspace_next(struct sway_workspace *current); |
74 | 75 | ||
75 | struct sway_workspace *workspace_output_prev( | 76 | struct sway_workspace *workspace_output_prev(struct sway_workspace *current); |
76 | struct sway_workspace *current, bool create); | ||
77 | 77 | ||
78 | struct sway_workspace *workspace_prev(struct sway_workspace *current); | 78 | struct sway_workspace *workspace_prev(struct sway_workspace *current); |
79 | 79 | ||
diff --git a/include/swaybar/i3bar.h b/include/swaybar/i3bar.h index df8cdd09..1aec6d6c 100644 --- a/include/swaybar/i3bar.h +++ b/include/swaybar/i3bar.h | |||
@@ -19,6 +19,7 @@ struct i3bar_block { | |||
19 | // Airblader features | 19 | // Airblader features |
20 | uint32_t background; | 20 | uint32_t background; |
21 | uint32_t border; | 21 | uint32_t border; |
22 | bool border_set; | ||
22 | int border_top; | 23 | int border_top; |
23 | int border_bottom; | 24 | int border_bottom; |
24 | int border_left; | 25 | int border_left; |
diff --git a/include/swaynag/types.h b/include/swaynag/types.h index 24da9418..3c3b2754 100644 --- a/include/swaynag/types.h +++ b/include/swaynag/types.h | |||
@@ -7,6 +7,7 @@ struct swaynag_type { | |||
7 | char *font; | 7 | char *font; |
8 | char *output; | 8 | char *output; |
9 | uint32_t anchors; | 9 | uint32_t anchors; |
10 | int32_t layer; // enum zwlr_layer_shell_v1_layer or -1 if unset | ||
10 | 11 | ||
11 | // Colors | 12 | // Colors |
12 | uint32_t button_text; | 13 | uint32_t button_text; |
diff --git a/include/util.h b/include/util.h index c80da1cb..f887d489 100644 --- a/include/util.h +++ b/include/util.h | |||
@@ -30,12 +30,6 @@ int parse_movement_amount(int argc, char **argv, | |||
30 | struct movement_amount *amount); | 30 | struct movement_amount *amount); |
31 | 31 | ||
32 | /** | 32 | /** |
33 | * Get the current time, in milliseconds. | ||
34 | */ | ||
35 | |||
36 | uint32_t get_current_time_msec(void); | ||
37 | |||
38 | /** | ||
39 | * Wrap i into the range [0, max] | 33 | * Wrap i into the range [0, max] |
40 | */ | 34 | */ |
41 | int wrap(int i, int max); | 35 | int wrap(int i, int max); |
diff --git a/meson.build b/meson.build index 38a55678..436b84d1 100644 --- a/meson.build +++ b/meson.build | |||
@@ -1,9 +1,9 @@ | |||
1 | project( | 1 | project( |
2 | 'sway', | 2 | 'sway', |
3 | 'c', | 3 | 'c', |
4 | version: '1.5', #release_version | 4 | version: '1.6', |
5 | license: 'MIT', | 5 | license: 'MIT', |
6 | meson_version: '>=0.53.0', | 6 | meson_version: '>=0.59.0', |
7 | default_options: [ | 7 | default_options: [ |
8 | 'c_std=c11', | 8 | 'c_std=c11', |
9 | 'warning_level=2', | 9 | 'warning_level=2', |
@@ -35,57 +35,54 @@ if is_freebsd | |||
35 | add_project_arguments('-D_C11_SOURCE', language: 'c') | 35 | add_project_arguments('-D_C11_SOURCE', language: 'c') |
36 | endif | 36 | endif |
37 | 37 | ||
38 | jsonc = dependency('json-c', version: '>=0.13') | 38 | jsonc = dependency('json-c', version: '>=0.13') |
39 | pcre = dependency('libpcre') | 39 | pcre = dependency('libpcre') |
40 | wayland_server = dependency('wayland-server') | 40 | wayland_server = dependency('wayland-server') |
41 | wayland_client = dependency('wayland-client') | 41 | wayland_client = dependency('wayland-client') |
42 | wayland_cursor = dependency('wayland-cursor') | 42 | wayland_cursor = dependency('wayland-cursor') |
43 | wayland_egl = dependency('wayland-egl') | 43 | wayland_egl = dependency('wayland-egl') |
44 | wayland_protos = dependency('wayland-protocols', version: '>=1.14') | 44 | wayland_protos = dependency('wayland-protocols', version: '>=1.14') |
45 | xkbcommon = dependency('xkbcommon') | 45 | xkbcommon = dependency('xkbcommon') |
46 | cairo = dependency('cairo') | 46 | cairo = dependency('cairo') |
47 | pango = dependency('pango') | 47 | pango = dependency('pango') |
48 | pangocairo = dependency('pangocairo') | 48 | pangocairo = dependency('pangocairo') |
49 | gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf')) | 49 | gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf')) |
50 | pixman = dependency('pixman-1') | 50 | pixman = dependency('pixman-1') |
51 | glesv2 = dependency('glesv2') | 51 | glesv2 = dependency('glesv2') |
52 | libevdev = dependency('libevdev') | 52 | libevdev = dependency('libevdev') |
53 | libinput = dependency('libinput', version: '>=1.6.0') | 53 | libinput = dependency('libinput', version: '>=1.6.0') |
54 | xcb = dependency('xcb', required: get_option('xwayland')) | 54 | xcb = dependency('xcb', required: get_option('xwayland')) |
55 | bash_comp = dependency('bash-completion', required: false) | 55 | drm_full = dependency('libdrm') # only needed for drm_fourcc.h |
56 | fish_comp = dependency('fish', required: false) | 56 | drm = drm_full.partial_dependency(compile_args: true, includes: true) |
57 | math = cc.find_library('m') | 57 | libudev = dependency('libudev') |
58 | rt = cc.find_library('rt') | 58 | bash_comp = dependency('bash-completion', required: false) |
59 | fish_comp = dependency('fish', required: false) | ||
60 | math = cc.find_library('m') | ||
61 | rt = cc.find_library('rt') | ||
59 | 62 | ||
60 | # Try first to find wlroots as a subproject, then as a system dependency | 63 | # Try first to find wlroots as a subproject, then as a system dependency |
61 | wlroots_version = ['>=0.12.0', '<0.13.0'] | 64 | wlroots_version = ['>=0.15.0', '<0.16.0'] |
62 | wlroots_proj = subproject( | 65 | wlroots_proj = subproject( |
63 | 'wlroots', | 66 | 'wlroots', |
64 | default_options: ['examples=false'], | 67 | default_options: ['examples=false'], |
65 | required: false, | 68 | required: false, |
66 | version: wlroots_version, | 69 | version: wlroots_version, |
67 | ) | 70 | ) |
68 | wlroots_features = { | ||
69 | 'xwayland': false, | ||
70 | 'systemd': false, | ||
71 | 'elogind': false, | ||
72 | 'libseat': false, | ||
73 | } | ||
74 | if wlroots_proj.found() | 71 | if wlroots_proj.found() |
75 | wlroots = wlroots_proj.get_variable('wlroots') | 72 | wlroots = wlroots_proj.get_variable('wlroots') |
76 | wlroots_conf = wlroots_proj.get_variable('conf_data') | ||
77 | foreach name, _ : wlroots_features | ||
78 | has = wlroots_conf.get('WLR_HAS_' + name.to_upper()) == 1 | ||
79 | wlroots_features += { name: has } | ||
80 | endforeach | ||
81 | else | 73 | else |
82 | wlroots = dependency('wlroots', version: wlroots_version) | 74 | wlroots = dependency('wlroots', version: wlroots_version) |
83 | foreach name, _ : wlroots_features | ||
84 | has = cc.get_define('WLR_HAS_' + name.to_upper(), prefix: '#include <wlr/config.h>', dependencies: wlroots) == '1' | ||
85 | wlroots_features += { name: has } | ||
86 | endforeach | ||
87 | endif | 75 | endif |
88 | 76 | ||
77 | wlroots_features = { | ||
78 | 'xwayland': false, | ||
79 | } | ||
80 | foreach name, _ : wlroots_features | ||
81 | var_name = 'have_' + name.underscorify() | ||
82 | have = wlroots.get_variable(pkgconfig: var_name, internal: var_name) == 'true' | ||
83 | wlroots_features += { name: have } | ||
84 | endforeach | ||
85 | |||
89 | if get_option('xwayland').enabled() and not wlroots_features['xwayland'] | 86 | if get_option('xwayland').enabled() and not wlroots_features['xwayland'] |
90 | error('Cannot enable Xwayland in sway: wlroots has been built without Xwayland support') | 87 | error('Cannot enable Xwayland in sway: wlroots has been built without Xwayland support') |
91 | endif | 88 | endif |
@@ -131,8 +128,7 @@ conf_data.set10('HAVE_TRAY', have_tray) | |||
131 | 128 | ||
132 | scdoc = dependency('scdoc', version: '>=1.9.2', native: true, required: get_option('man-pages')) | 129 | scdoc = dependency('scdoc', version: '>=1.9.2', native: true, required: get_option('man-pages')) |
133 | if scdoc.found() | 130 | if scdoc.found() |
134 | scdoc_prog = find_program(scdoc.get_pkgconfig_variable('scdoc'), native: true) | 131 | scdoc_prog = find_program(scdoc.get_variable(pkgconfig: 'scdoc'), native: true) |
135 | sh = find_program('sh', native: true) | ||
136 | mandir = get_option('mandir') | 132 | mandir = get_option('mandir') |
137 | man_files = [ | 133 | man_files = [ |
138 | 'sway/sway.1.scd', | 134 | 'sway/sway.1.scd', |
@@ -143,9 +139,15 @@ if scdoc.found() | |||
143 | 'sway/sway-output.5.scd', | 139 | 'sway/sway-output.5.scd', |
144 | 'swaybar/swaybar-protocol.7.scd', | 140 | 'swaybar/swaybar-protocol.7.scd', |
145 | 'swaymsg/swaymsg.1.scd', | 141 | 'swaymsg/swaymsg.1.scd', |
146 | 'swaynag/swaynag.1.scd', | ||
147 | 'swaynag/swaynag.5.scd', | ||
148 | ] | 142 | ] |
143 | |||
144 | if get_option('swaynag') | ||
145 | man_files += [ | ||
146 | 'swaynag/swaynag.1.scd', | ||
147 | 'swaynag/swaynag.5.scd', | ||
148 | ] | ||
149 | endif | ||
150 | |||
149 | foreach filename : man_files | 151 | foreach filename : man_files |
150 | topic = filename.split('.')[-3].split('/')[-1] | 152 | topic = filename.split('.')[-3].split('/')[-1] |
151 | section = filename.split('.')[-2] | 153 | section = filename.split('.')[-2] |
@@ -155,10 +157,10 @@ if scdoc.found() | |||
155 | output, | 157 | output, |
156 | input: filename, | 158 | input: filename, |
157 | output: output, | 159 | output: output, |
158 | command: [ | 160 | command: scdoc_prog, |
159 | sh, '-c', '@0@ < @INPUT@ > @1@'.format(scdoc_prog.path(), output) | ||
160 | ], | ||
161 | install: true, | 161 | install: true, |
162 | feed: true, | ||
163 | capture: true, | ||
162 | install_dir: '@0@/man@1@'.format(mandir, section) | 164 | install_dir: '@0@/man@1@'.format(mandir, section) |
163 | ) | 165 | ) |
164 | endforeach | 166 | endforeach |
@@ -183,7 +185,7 @@ add_project_arguments('-DSWAY_VERSION=@0@'.format(version), language: 'c') | |||
183 | 185 | ||
184 | # Compute the relative path used by compiler invocations. | 186 | # Compute the relative path used by compiler invocations. |
185 | source_root = meson.current_source_dir().split('/') | 187 | source_root = meson.current_source_dir().split('/') |
186 | build_root = meson.build_root().split('/') | 188 | build_root = meson.global_build_root().split('/') |
187 | relative_dir_parts = [] | 189 | relative_dir_parts = [] |
188 | i = 0 | 190 | i = 0 |
189 | in_prefix = true | 191 | in_prefix = true |
@@ -227,9 +229,15 @@ subdir('common') | |||
227 | subdir('sway') | 229 | subdir('sway') |
228 | subdir('swaymsg') | 230 | subdir('swaymsg') |
229 | 231 | ||
230 | subdir('client') | 232 | if get_option('swaybar') or get_option('swaynag') |
231 | subdir('swaybar') | 233 | subdir('client') |
232 | subdir('swaynag') | 234 | endif |
235 | if get_option('swaybar') | ||
236 | subdir('swaybar') | ||
237 | endif | ||
238 | if get_option('swaynag') | ||
239 | subdir('swaynag') | ||
240 | endif | ||
233 | 241 | ||
234 | config = configuration_data() | 242 | config = configuration_data() |
235 | config.set('datadir', join_paths(prefix, datadir)) | 243 | config.set('datadir', join_paths(prefix, datadir)) |
@@ -277,13 +285,17 @@ endif | |||
277 | if get_option('bash-completions') | 285 | if get_option('bash-completions') |
278 | bash_files = files( | 286 | bash_files = files( |
279 | 'completions/bash/sway', | 287 | 'completions/bash/sway', |
280 | 'completions/bash/swaybar', | ||
281 | 'completions/bash/swaymsg', | 288 | 'completions/bash/swaymsg', |
282 | ) | 289 | ) |
290 | |||
291 | if get_option('swaybar') | ||
292 | bash_files += files('completions/bash/swaybar') | ||
293 | endif | ||
294 | |||
283 | if bash_comp.found() | 295 | if bash_comp.found() |
284 | bash_install_dir = bash_comp.get_pkgconfig_variable( | 296 | bash_install_dir = bash_comp.get_variable( |
285 | 'completionsdir', | 297 | pkgconfig: 'completionsdir', |
286 | define_variable: ['datadir', datadir] | 298 | pkgconfig_define: ['datadir', datadir] |
287 | ) | 299 | ) |
288 | else | 300 | else |
289 | bash_install_dir = join_paths(datadir, 'bash-completion', 'completions') | 301 | bash_install_dir = join_paths(datadir, 'bash-completion', 'completions') |
@@ -296,12 +308,16 @@ if get_option('fish-completions') | |||
296 | fish_files = files( | 308 | fish_files = files( |
297 | 'completions/fish/sway.fish', | 309 | 'completions/fish/sway.fish', |
298 | 'completions/fish/swaymsg.fish', | 310 | 'completions/fish/swaymsg.fish', |
299 | 'completions/fish/swaynag.fish', | ||
300 | ) | 311 | ) |
312 | |||
313 | if get_option('swaynag') | ||
314 | fish_files += files('completions/fish/swaynag.fish') | ||
315 | endif | ||
316 | |||
301 | if fish_comp.found() | 317 | if fish_comp.found() |
302 | fish_install_dir = fish_comp.get_pkgconfig_variable( | 318 | fish_install_dir = fish_comp.get_variable( |
303 | 'completionsdir', | 319 | pkgconfig: 'completionsdir', |
304 | define_variable: ['datadir', datadir] | 320 | pkgconfig_define: ['datadir', datadir] |
305 | ) | 321 | ) |
306 | else | 322 | else |
307 | fish_install_dir = join_paths(datadir, 'fish', 'vendor_completions.d') | 323 | fish_install_dir = join_paths(datadir, 'fish', 'vendor_completions.d') |
@@ -313,12 +329,7 @@ endif | |||
313 | summary({ | 329 | summary({ |
314 | 'xwayland': have_xwayland, | 330 | 'xwayland': have_xwayland, |
315 | 'gdk-pixbuf': gdk_pixbuf.found(), | 331 | 'gdk-pixbuf': gdk_pixbuf.found(), |
316 | 'sd-bus': sdbus.found(), | ||
317 | 'tray': have_tray, | 332 | 'tray': have_tray, |
318 | 'man-pages': scdoc.found(), | 333 | 'man-pages': scdoc.found(), |
319 | }, bool_yn: true) | 334 | }, bool_yn: true) |
320 | 335 | ||
321 | if not wlroots_features['systemd'] and not wlroots_features['elogind'] and not wlroots_features['libseat'] | ||
322 | warning('The sway binary must be setuid when compiled without (e)logind or libseat') | ||
323 | warning('You must do this manually post-install: chmod a+s /path/to/sway') | ||
324 | endif | ||
diff --git a/meson_options.txt b/meson_options.txt index e36900b6..6ba67554 100644 --- a/meson_options.txt +++ b/meson_options.txt | |||
@@ -2,6 +2,8 @@ option('default-wallpaper', type: 'boolean', value: true, description: 'Install | |||
2 | option('zsh-completions', type: 'boolean', value: true, description: 'Install zsh shell completions.') | 2 | option('zsh-completions', type: 'boolean', value: true, description: 'Install zsh shell completions.') |
3 | option('bash-completions', type: 'boolean', value: true, description: 'Install bash shell completions.') | 3 | option('bash-completions', type: 'boolean', value: true, description: 'Install bash shell completions.') |
4 | option('fish-completions', type: 'boolean', value: true, description: 'Install fish shell completions.') | 4 | option('fish-completions', type: 'boolean', value: true, description: 'Install fish shell completions.') |
5 | option('swaybar', type: 'boolean', value: true, description: 'Enable support for swaybar') | ||
6 | option('swaynag', type: 'boolean', value: true, description: 'Enable support for swaynag') | ||
5 | option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications') | 7 | option('xwayland', type: 'feature', value: 'auto', description: 'Enable support for X11 applications') |
6 | option('tray', type: 'feature', value: 'auto', description: 'Enable support for swaybar tray') | 8 | option('tray', type: 'feature', value: 'auto', description: 'Enable support for swaybar tray') |
7 | option('gdk-pixbuf', type: 'feature', value: 'auto', description: 'Enable support for more image formats in swaybg') | 9 | option('gdk-pixbuf', type: 'feature', value: 'auto', description: 'Enable support for more image formats in swaybg') |
diff --git a/protocols/meson.build b/protocols/meson.build index 124e9777..8e9e65be 100644 --- a/protocols/meson.build +++ b/protocols/meson.build | |||
@@ -1,9 +1,9 @@ | |||
1 | wl_protocol_dir = wayland_protos.get_pkgconfig_variable('pkgdatadir') | 1 | wl_protocol_dir = wayland_protos.get_variable('pkgdatadir') |
2 | 2 | ||
3 | wayland_scanner_dep = dependency('wayland-scanner', required: false, native: true) | 3 | wayland_scanner_dep = dependency('wayland-scanner', required: false, native: true) |
4 | if wayland_scanner_dep.found() | 4 | if wayland_scanner_dep.found() |
5 | wayland_scanner = find_program( | 5 | wayland_scanner = find_program( |
6 | wayland_scanner_dep.get_pkgconfig_variable('wayland_scanner'), | 6 | wayland_scanner_dep.get_variable(pkgconfig: 'wayland_scanner'), |
7 | native: true, | 7 | native: true, |
8 | ) | 8 | ) |
9 | else | 9 | else |
diff --git a/sway/commands.c b/sway/commands.c index fe1e98b5..205406ad 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 | |||
42 | } | 42 | } |
43 | 43 | ||
44 | /* Keep alphabetized */ | 44 | /* Keep alphabetized */ |
45 | static struct cmd_handler handlers[] = { | 45 | static const struct cmd_handler handlers[] = { |
46 | { "assign", cmd_assign }, | 46 | { "assign", cmd_assign }, |
47 | { "bar", cmd_bar }, | 47 | { "bar", cmd_bar }, |
48 | { "bindcode", cmd_bindcode }, | 48 | { "bindcode", cmd_bindcode }, |
@@ -98,7 +98,7 @@ static struct cmd_handler handlers[] = { | |||
98 | }; | 98 | }; |
99 | 99 | ||
100 | /* Config-time only commands. Keep alphabetized */ | 100 | /* Config-time only commands. Keep alphabetized */ |
101 | static struct cmd_handler config_handlers[] = { | 101 | static const struct cmd_handler config_handlers[] = { |
102 | { "default_orientation", cmd_default_orientation }, | 102 | { "default_orientation", cmd_default_orientation }, |
103 | { "include", cmd_include }, | 103 | { "include", cmd_include }, |
104 | { "swaybg_command", cmd_swaybg_command }, | 104 | { "swaybg_command", cmd_swaybg_command }, |
@@ -108,7 +108,7 @@ static struct cmd_handler config_handlers[] = { | |||
108 | }; | 108 | }; |
109 | 109 | ||
110 | /* Runtime-only commands. Keep alphabetized */ | 110 | /* Runtime-only commands. Keep alphabetized */ |
111 | static struct cmd_handler command_handlers[] = { | 111 | static const struct cmd_handler command_handlers[] = { |
112 | { "border", cmd_border }, | 112 | { "border", cmd_border }, |
113 | { "create_output", cmd_create_output }, | 113 | { "create_output", cmd_create_output }, |
114 | { "exit", cmd_exit }, | 114 | { "exit", cmd_exit }, |
@@ -144,22 +144,22 @@ static int handler_compare(const void *_a, const void *_b) { | |||
144 | return strcasecmp(a->command, b->command); | 144 | return strcasecmp(a->command, b->command); |
145 | } | 145 | } |
146 | 146 | ||
147 | struct cmd_handler *find_handler(char *line, struct cmd_handler *handlers, | 147 | const struct cmd_handler *find_handler(char *line, |
148 | size_t handlers_size) { | 148 | const struct cmd_handler *handlers, size_t handlers_size) { |
149 | if (!handlers || !handlers_size) { | 149 | if (!handlers || !handlers_size) { |
150 | return NULL; | 150 | return NULL; |
151 | } | 151 | } |
152 | struct cmd_handler query = { .command = line }; | 152 | const struct cmd_handler query = { .command = line }; |
153 | return bsearch(&query, handlers, | 153 | return bsearch(&query, handlers, |
154 | handlers_size / sizeof(struct cmd_handler), | 154 | handlers_size / sizeof(struct cmd_handler), |
155 | sizeof(struct cmd_handler), handler_compare); | 155 | sizeof(struct cmd_handler), handler_compare); |
156 | } | 156 | } |
157 | 157 | ||
158 | static struct cmd_handler *find_handler_ex(char *line, | 158 | static const struct cmd_handler *find_handler_ex(char *line, |
159 | struct cmd_handler *config_handlers, size_t config_handlers_size, | 159 | const struct cmd_handler *config_handlers, size_t config_handlers_size, |
160 | struct cmd_handler *command_handlers, size_t command_handlers_size, | 160 | const struct cmd_handler *command_handlers, size_t command_handlers_size, |
161 | struct cmd_handler *handlers, size_t handlers_size) { | 161 | const struct cmd_handler *handlers, size_t handlers_size) { |
162 | struct cmd_handler *handler = NULL; | 162 | const struct cmd_handler *handler = NULL; |
163 | if (config->reading) { | 163 | if (config->reading) { |
164 | handler = find_handler(line, config_handlers, config_handlers_size); | 164 | handler = find_handler(line, config_handlers, config_handlers_size); |
165 | } else if (config->active) { | 165 | } else if (config->active) { |
@@ -168,16 +168,17 @@ static struct cmd_handler *find_handler_ex(char *line, | |||
168 | return handler ? handler : find_handler(line, handlers, handlers_size); | 168 | return handler ? handler : find_handler(line, handlers, handlers_size); |
169 | } | 169 | } |
170 | 170 | ||
171 | static struct cmd_handler *find_core_handler(char *line) { | 171 | static const struct cmd_handler *find_core_handler(char *line) { |
172 | return find_handler_ex(line, config_handlers, sizeof(config_handlers), | 172 | return find_handler_ex(line, config_handlers, sizeof(config_handlers), |
173 | command_handlers, sizeof(command_handlers), | 173 | command_handlers, sizeof(command_handlers), |
174 | handlers, sizeof(handlers)); | 174 | handlers, sizeof(handlers)); |
175 | } | 175 | } |
176 | 176 | ||
177 | static void set_config_node(struct sway_node *node) { | 177 | static void set_config_node(struct sway_node *node, bool node_overridden) { |
178 | config->handler_context.node = node; | 178 | config->handler_context.node = node; |
179 | config->handler_context.container = NULL; | 179 | config->handler_context.container = NULL; |
180 | config->handler_context.workspace = NULL; | 180 | config->handler_context.workspace = NULL; |
181 | config->handler_context.node_overridden = node_overridden; | ||
181 | 182 | ||
182 | if (node == NULL) { | 183 | if (node == NULL) { |
183 | return; | 184 | return; |
@@ -186,7 +187,7 @@ static void set_config_node(struct sway_node *node) { | |||
186 | switch (node->type) { | 187 | switch (node->type) { |
187 | case N_CONTAINER: | 188 | case N_CONTAINER: |
188 | config->handler_context.container = node->sway_container; | 189 | config->handler_context.container = node->sway_container; |
189 | config->handler_context.workspace = node->sway_container->workspace; | 190 | config->handler_context.workspace = node->sway_container->pending.workspace; |
190 | break; | 191 | break; |
191 | case N_WORKSPACE: | 192 | case N_WORKSPACE: |
192 | config->handler_context.workspace = node->sway_workspace; | 193 | config->handler_context.workspace = node->sway_workspace; |
@@ -202,6 +203,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat, | |||
202 | char *cmd; | 203 | char *cmd; |
203 | char matched_delim = ';'; | 204 | char matched_delim = ';'; |
204 | list_t *containers = NULL; | 205 | list_t *containers = NULL; |
206 | bool using_criteria = false; | ||
205 | 207 | ||
206 | if (seat == NULL) { | 208 | if (seat == NULL) { |
207 | // passing a NULL seat means we just pick the default seat | 209 | // 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, | |||
225 | for (; isspace(*head); ++head) {} | 227 | for (; isspace(*head); ++head) {} |
226 | // Extract criteria (valid for this command list only). | 228 | // Extract criteria (valid for this command list only). |
227 | if (matched_delim == ';') { | 229 | if (matched_delim == ';') { |
228 | config->handler_context.using_criteria = false; | 230 | using_criteria = false; |
229 | if (*head == '[') { | 231 | if (*head == '[') { |
230 | char *error = NULL; | 232 | char *error = NULL; |
231 | struct criteria *criteria = criteria_parse(head, &error); | 233 | struct criteria *criteria = criteria_parse(head, &error); |
@@ -239,7 +241,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat, | |||
239 | containers = criteria_get_containers(criteria); | 241 | containers = criteria_get_containers(criteria); |
240 | head += strlen(criteria->raw); | 242 | head += strlen(criteria->raw); |
241 | criteria_destroy(criteria); | 243 | criteria_destroy(criteria); |
242 | config->handler_context.using_criteria = true; | 244 | using_criteria = true; |
243 | // Skip leading whitespace | 245 | // Skip leading whitespace |
244 | for (; isspace(*head); ++head) {} | 246 | for (; isspace(*head); ++head) {} |
245 | } | 247 | } |
@@ -265,7 +267,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat, | |||
265 | } | 267 | } |
266 | } | 268 | } |
267 | } | 269 | } |
268 | struct cmd_handler *handler = find_core_handler(argv[0]); | 270 | const struct cmd_handler *handler = find_core_handler(argv[0]); |
269 | if (!handler) { | 271 | if (!handler) { |
270 | list_add(res_list, cmd_results_new(CMD_INVALID, | 272 | list_add(res_list, cmd_results_new(CMD_INVALID, |
271 | "Unknown/invalid command '%s'", argv[0])); | 273 | "Unknown/invalid command '%s'", argv[0])); |
@@ -278,11 +280,14 @@ list_t *execute_command(char *_exec, struct sway_seat *seat, | |||
278 | argv[i] = do_var_replacement(argv[i]); | 280 | argv[i] = do_var_replacement(argv[i]); |
279 | } | 281 | } |
280 | 282 | ||
281 | if (!config->handler_context.using_criteria) { | 283 | |
282 | // The container or workspace which this command will run on. | 284 | if (!using_criteria) { |
283 | struct sway_node *node = con ? &con->node : | 285 | if (con) { |
284 | seat_get_focus_inactive(seat, &root->node); | 286 | set_config_node(&con->node, true); |
285 | set_config_node(node); | 287 | } else { |
288 | set_config_node(seat_get_focus_inactive(seat, &root->node), | ||
289 | false); | ||
290 | } | ||
286 | struct cmd_results *res = handler->handle(argc-1, argv+1); | 291 | struct cmd_results *res = handler->handle(argc-1, argv+1); |
287 | list_add(res_list, res); | 292 | list_add(res_list, res); |
288 | if (res->status == CMD_INVALID) { | 293 | if (res->status == CMD_INVALID) { |
@@ -296,7 +301,7 @@ list_t *execute_command(char *_exec, struct sway_seat *seat, | |||
296 | struct cmd_results *fail_res = NULL; | 301 | struct cmd_results *fail_res = NULL; |
297 | for (int i = 0; i < containers->length; ++i) { | 302 | for (int i = 0; i < containers->length; ++i) { |
298 | struct sway_container *container = containers->items[i]; | 303 | struct sway_container *container = containers->items[i]; |
299 | set_config_node(&container->node); | 304 | set_config_node(&container->node, true); |
300 | struct cmd_results *res = handler->handle(argc-1, argv+1); | 305 | struct cmd_results *res = handler->handle(argc-1, argv+1); |
301 | if (res->status == CMD_SUCCESS) { | 306 | if (res->status == CMD_SUCCESS) { |
302 | free_cmd_results(res); | 307 | free_cmd_results(res); |
@@ -370,7 +375,7 @@ struct cmd_results *config_command(char *exec, char **new_block) { | |||
370 | 375 | ||
371 | // Determine the command handler | 376 | // Determine the command handler |
372 | sway_log(SWAY_INFO, "Config command: %s", exec); | 377 | sway_log(SWAY_INFO, "Config command: %s", exec); |
373 | struct cmd_handler *handler = find_core_handler(argv[0]); | 378 | const struct cmd_handler *handler = find_core_handler(argv[0]); |
374 | if (!handler || !handler->handle) { | 379 | if (!handler || !handler->handle) { |
375 | const char *error = handler | 380 | const char *error = handler |
376 | ? "Command '%s' is shimmed, but unimplemented" | 381 | ? "Command '%s' is shimmed, but unimplemented" |
@@ -418,12 +423,12 @@ cleanup: | |||
418 | } | 423 | } |
419 | 424 | ||
420 | struct cmd_results *config_subcommand(char **argv, int argc, | 425 | struct cmd_results *config_subcommand(char **argv, int argc, |
421 | struct cmd_handler *handlers, size_t handlers_size) { | 426 | const struct cmd_handler *handlers, size_t handlers_size) { |
422 | char *command = join_args(argv, argc); | 427 | char *command = join_args(argv, argc); |
423 | sway_log(SWAY_DEBUG, "Subcommand: %s", command); | 428 | sway_log(SWAY_DEBUG, "Subcommand: %s", command); |
424 | free(command); | 429 | free(command); |
425 | 430 | ||
426 | struct cmd_handler *handler = find_handler(argv[0], handlers, | 431 | const struct cmd_handler *handler = find_handler(argv[0], handlers, |
427 | handlers_size); | 432 | handlers_size); |
428 | if (!handler) { | 433 | if (!handler) { |
429 | return cmd_results_new(CMD_INVALID, | 434 | return cmd_results_new(CMD_INVALID, |
@@ -453,41 +458,13 @@ struct cmd_results *config_commands_command(char *exec) { | |||
453 | goto cleanup; | 458 | goto cleanup; |
454 | } | 459 | } |
455 | 460 | ||
456 | struct cmd_handler *handler = find_handler(cmd, NULL, 0); | 461 | const struct cmd_handler *handler = find_handler(cmd, NULL, 0); |
457 | if (!handler && strcmp(cmd, "*") != 0) { | 462 | if (!handler && strcmp(cmd, "*") != 0) { |
458 | results = cmd_results_new(CMD_INVALID, | 463 | results = cmd_results_new(CMD_INVALID, |
459 | "Unknown/invalid command '%s'", cmd); | 464 | "Unknown/invalid command '%s'", cmd); |
460 | goto cleanup; | 465 | goto cleanup; |
461 | } | 466 | } |
462 | 467 | ||
463 | enum command_context context = 0; | ||
464 | |||
465 | struct { | ||
466 | char *name; | ||
467 | enum command_context context; | ||
468 | } context_names[] = { | ||
469 | { "config", CONTEXT_CONFIG }, | ||
470 | { "binding", CONTEXT_BINDING }, | ||
471 | { "ipc", CONTEXT_IPC }, | ||
472 | { "criteria", CONTEXT_CRITERIA }, | ||
473 | { "all", CONTEXT_ALL }, | ||
474 | }; | ||
475 | |||
476 | for (int i = 1; i < argc; ++i) { | ||
477 | size_t j; | ||
478 | for (j = 0; j < sizeof(context_names) / sizeof(context_names[0]); ++j) { | ||
479 | if (strcmp(context_names[j].name, argv[i]) == 0) { | ||
480 | break; | ||
481 | } | ||
482 | } | ||
483 | if (j == sizeof(context_names) / sizeof(context_names[0])) { | ||
484 | results = cmd_results_new(CMD_INVALID, | ||
485 | "Invalid command context %s", argv[i]); | ||
486 | goto cleanup; | ||
487 | } | ||
488 | context |= context_names[j].context; | ||
489 | } | ||
490 | |||
491 | results = cmd_results_new(CMD_SUCCESS, NULL); | 468 | results = cmd_results_new(CMD_SUCCESS, NULL); |
492 | 469 | ||
493 | cleanup: | 470 | cleanup: |
diff --git a/sway/commands/bar.c b/sway/commands/bar.c index d42b7fc2..8571d282 100644 --- a/sway/commands/bar.c +++ b/sway/commands/bar.c | |||
@@ -8,7 +8,7 @@ | |||
8 | #include "log.h" | 8 | #include "log.h" |
9 | 9 | ||
10 | // Must be in alphabetical order for bsearch | 10 | // Must be in alphabetical order for bsearch |
11 | static struct cmd_handler bar_handlers[] = { | 11 | static const struct cmd_handler bar_handlers[] = { |
12 | { "bindcode", bar_cmd_bindcode }, | 12 | { "bindcode", bar_cmd_bindcode }, |
13 | { "binding_mode_indicator", bar_cmd_binding_mode_indicator }, | 13 | { "binding_mode_indicator", bar_cmd_binding_mode_indicator }, |
14 | { "bindsym", bar_cmd_bindsym }, | 14 | { "bindsym", bar_cmd_bindsym }, |
@@ -41,7 +41,7 @@ static struct cmd_handler bar_handlers[] = { | |||
41 | }; | 41 | }; |
42 | 42 | ||
43 | // Must be in alphabetical order for bsearch | 43 | // Must be in alphabetical order for bsearch |
44 | static struct cmd_handler bar_config_handlers[] = { | 44 | static const struct cmd_handler bar_config_handlers[] = { |
45 | { "id", bar_cmd_id }, | 45 | { "id", bar_cmd_id }, |
46 | { "swaybar_command", bar_cmd_swaybar_command }, | 46 | { "swaybar_command", bar_cmd_swaybar_command }, |
47 | }; | 47 | }; |
@@ -116,6 +116,7 @@ struct cmd_results *cmd_bar(int argc, char **argv) { | |||
116 | if (res && res->status != CMD_SUCCESS) { | 116 | if (res && res->status != CMD_SUCCESS) { |
117 | if (id) { | 117 | if (id) { |
118 | free_bar_config(config->current_bar); | 118 | free_bar_config(config->current_bar); |
119 | config->current_bar = NULL; | ||
119 | id = NULL; | 120 | id = NULL; |
120 | } | 121 | } |
121 | return res; | 122 | return res; |
diff --git a/sway/commands/bar/colors.c b/sway/commands/bar/colors.c index 2d5b22bf..275fa3c6 100644 --- a/sway/commands/bar/colors.c +++ b/sway/commands/bar/colors.c | |||
@@ -4,7 +4,7 @@ | |||
4 | #include "util.h" | 4 | #include "util.h" |
5 | 5 | ||
6 | // Must be in alphabetical order for bsearch | 6 | // Must be in alphabetical order for bsearch |
7 | static struct cmd_handler bar_colors_handlers[] = { | 7 | static const struct cmd_handler bar_colors_handlers[] = { |
8 | { "active_workspace", bar_colors_cmd_active_workspace }, | 8 | { "active_workspace", bar_colors_cmd_active_workspace }, |
9 | { "background", bar_colors_cmd_background }, | 9 | { "background", bar_colors_cmd_background }, |
10 | { "binding_mode", bar_colors_cmd_binding_mode }, | 10 | { "binding_mode", bar_colors_cmd_binding_mode }, |
diff --git a/sway/commands/bar/font.c b/sway/commands/bar/font.c index 62987f3e..891c87af 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) { | |||
11 | } | 11 | } |
12 | char *font = join_args(argv, argc); | 12 | char *font = join_args(argv, argc); |
13 | free(config->current_bar->font); | 13 | free(config->current_bar->font); |
14 | config->current_bar->font = font; | 14 | |
15 | if (strncmp(font, "pango:", 6) == 0) { | ||
16 | if (config->current_bar->pango_markup == PANGO_MARKUP_DEFAULT) { | ||
17 | config->current_bar->pango_markup = true; | ||
18 | } | ||
19 | config->current_bar->font = strdup(font + 6); | ||
20 | } else { | ||
21 | if (config->current_bar->pango_markup == PANGO_MARKUP_DEFAULT) { | ||
22 | config->current_bar->pango_markup = false; | ||
23 | } | ||
24 | config->current_bar->font = strdup(font); | ||
25 | } | ||
26 | |||
27 | free(font); | ||
15 | sway_log(SWAY_DEBUG, "Settings font '%s' for bar: %s", | 28 | sway_log(SWAY_DEBUG, "Settings font '%s' for bar: %s", |
16 | config->current_bar->font, config->current_bar->id); | 29 | config->current_bar->font, config->current_bar->id); |
17 | return cmd_results_new(CMD_SUCCESS, NULL); | 30 | return cmd_results_new(CMD_SUCCESS, NULL); |
diff --git a/sway/commands/bind.c b/sway/commands/bind.c index f6e58d99..25be415e 100644 --- a/sway/commands/bind.c +++ b/sway/commands/bind.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <wlr/types/wlr_cursor.h> | 8 | #include <wlr/types/wlr_cursor.h> |
9 | #include "sway/commands.h" | 9 | #include "sway/commands.h" |
10 | #include "sway/config.h" | 10 | #include "sway/config.h" |
11 | #include "sway/desktop/transaction.h" | ||
11 | #include "sway/input/cursor.h" | 12 | #include "sway/input/cursor.h" |
12 | #include "sway/input/keyboard.h" | 13 | #include "sway/input/keyboard.h" |
13 | #include "sway/ipc-server.h" | 14 | #include "sway/ipc-server.h" |
@@ -559,8 +560,8 @@ struct cmd_results *cmd_bind_or_unbind_switch(int argc, char **argv, | |||
559 | free_switch_binding(binding); | 560 | free_switch_binding(binding); |
560 | return cmd_results_new(CMD_FAILURE, | 561 | return cmd_results_new(CMD_FAILURE, |
561 | "Invalid %s command " | 562 | "Invalid %s command " |
562 | "(expected switch state: unknown state %d)", | 563 | "(expected switch state: unknown state %s)", |
563 | bindtype, split->items[0]); | 564 | bindtype, split->items[1]); |
564 | } | 565 | } |
565 | list_free_items_and_destroy(split); | 566 | list_free_items_and_destroy(split); |
566 | 567 | ||
@@ -642,6 +643,8 @@ void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding) | |||
642 | if (success) { | 643 | if (success) { |
643 | ipc_event_binding(binding); | 644 | ipc_event_binding(binding); |
644 | } | 645 | } |
646 | |||
647 | transaction_commit_dirty(); | ||
645 | } | 648 | } |
646 | 649 | ||
647 | /** | 650 | /** |
diff --git a/sway/commands/border.c b/sway/commands/border.c index 647663ac..7818fc96 100644 --- a/sway/commands/border.c +++ b/sway/commands/border.c | |||
@@ -19,11 +19,11 @@ static void set_border(struct sway_container *con, | |||
19 | view_set_csd_from_server(con->view, false); | 19 | view_set_csd_from_server(con->view, false); |
20 | } else if (!con->view->using_csd && new_border == B_CSD) { | 20 | } else if (!con->view->using_csd && new_border == B_CSD) { |
21 | view_set_csd_from_server(con->view, true); | 21 | view_set_csd_from_server(con->view, true); |
22 | con->saved_border = con->border; | 22 | con->saved_border = con->pending.border; |
23 | } | 23 | } |
24 | } | 24 | } |
25 | if (new_border != B_CSD || container_is_floating(con)) { | 25 | if (new_border != B_CSD || container_is_floating(con)) { |
26 | con->border = new_border; | 26 | con->pending.border = new_border; |
27 | } | 27 | } |
28 | if (con->view) { | 28 | if (con->view) { |
29 | con->view->using_csd = new_border == B_CSD; | 29 | con->view->using_csd = new_border == B_CSD; |
@@ -35,7 +35,7 @@ static void border_toggle(struct sway_container *con) { | |||
35 | set_border(con, B_NONE); | 35 | set_border(con, B_NONE); |
36 | return; | 36 | return; |
37 | } | 37 | } |
38 | switch (con->border) { | 38 | switch (con->pending.border) { |
39 | case B_NONE: | 39 | case B_NONE: |
40 | set_border(con, B_PIXEL); | 40 | set_border(con, B_PIXEL); |
41 | break; | 41 | break; |
@@ -88,7 +88,7 @@ struct cmd_results *cmd_border(int argc, char **argv) { | |||
88 | "or 'border pixel <px>'"); | 88 | "or 'border pixel <px>'"); |
89 | } | 89 | } |
90 | if (argc == 2) { | 90 | if (argc == 2) { |
91 | container->border_thickness = atoi(argv[1]); | 91 | container->pending.border_thickness = atoi(argv[1]); |
92 | } | 92 | } |
93 | 93 | ||
94 | if (container_is_floating(container)) { | 94 | if (container_is_floating(container)) { |
diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c index 39e48a44..fce337d5 100644 --- a/sway/commands/exec_always.c +++ b/sway/commands/exec_always.c | |||
@@ -26,7 +26,7 @@ struct cmd_results *cmd_exec_validate(int argc, char **argv) { | |||
26 | 26 | ||
27 | struct cmd_results *cmd_exec_process(int argc, char **argv) { | 27 | struct cmd_results *cmd_exec_process(int argc, char **argv) { |
28 | struct cmd_results *error = NULL; | 28 | struct cmd_results *error = NULL; |
29 | char *tmp = NULL; | 29 | char *cmd = NULL; |
30 | if (strcmp(argv[0], "--no-startup-id") == 0) { | 30 | if (strcmp(argv[0], "--no-startup-id") == 0) { |
31 | sway_log(SWAY_INFO, "exec switch '--no-startup-id' not supported, ignored."); | 31 | sway_log(SWAY_INFO, "exec switch '--no-startup-id' not supported, ignored."); |
32 | --argc; ++argv; | 32 | --argc; ++argv; |
@@ -36,17 +36,12 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) { | |||
36 | } | 36 | } |
37 | 37 | ||
38 | if (argc == 1 && (argv[0][0] == '\'' || argv[0][0] == '"')) { | 38 | if (argc == 1 && (argv[0][0] == '\'' || argv[0][0] == '"')) { |
39 | tmp = strdup(argv[0]); | 39 | cmd = strdup(argv[0]); |
40 | strip_quotes(tmp); | 40 | strip_quotes(cmd); |
41 | } else { | 41 | } else { |
42 | tmp = join_args(argv, argc); | 42 | cmd = join_args(argv, argc); |
43 | } | 43 | } |
44 | 44 | ||
45 | // Put argument into cmd array | ||
46 | char cmd[4096]; | ||
47 | strncpy(cmd, tmp, sizeof(cmd) - 1); | ||
48 | cmd[sizeof(cmd) - 1] = 0; | ||
49 | free(tmp); | ||
50 | sway_log(SWAY_DEBUG, "Executing %s", cmd); | 45 | sway_log(SWAY_DEBUG, "Executing %s", cmd); |
51 | 46 | ||
52 | int fd[2]; | 47 | int fd[2]; |
@@ -62,11 +57,13 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) { | |||
62 | sigset_t set; | 57 | sigset_t set; |
63 | sigemptyset(&set); | 58 | sigemptyset(&set); |
64 | sigprocmask(SIG_SETMASK, &set, NULL); | 59 | sigprocmask(SIG_SETMASK, &set, NULL); |
60 | signal(SIGPIPE, SIG_DFL); | ||
65 | close(fd[0]); | 61 | close(fd[0]); |
66 | if ((child = fork()) == 0) { | 62 | if ((child = fork()) == 0) { |
67 | close(fd[1]); | 63 | close(fd[1]); |
68 | execl("/bin/sh", "/bin/sh", "-c", cmd, (void *)NULL); | 64 | execlp("sh", "sh", "-c", cmd, (void *)NULL); |
69 | _exit(0); | 65 | sway_log_errno(SWAY_ERROR, "execlp failed"); |
66 | _exit(1); | ||
70 | } | 67 | } |
71 | ssize_t s = 0; | 68 | ssize_t s = 0; |
72 | while ((size_t)s < sizeof(pid_t)) { | 69 | while ((size_t)s < sizeof(pid_t)) { |
@@ -75,10 +72,12 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) { | |||
75 | close(fd[1]); | 72 | close(fd[1]); |
76 | _exit(0); // Close child process | 73 | _exit(0); // Close child process |
77 | } else if (pid < 0) { | 74 | } else if (pid < 0) { |
75 | free(cmd); | ||
78 | close(fd[0]); | 76 | close(fd[0]); |
79 | close(fd[1]); | 77 | close(fd[1]); |
80 | return cmd_results_new(CMD_FAILURE, "fork() failed"); | 78 | return cmd_results_new(CMD_FAILURE, "fork() failed"); |
81 | } | 79 | } |
80 | free(cmd); | ||
82 | close(fd[1]); // close write | 81 | close(fd[1]); // close write |
83 | ssize_t s = 0; | 82 | ssize_t s = 0; |
84 | while ((size_t)s < sizeof(pid_t)) { | 83 | while ((size_t)s < sizeof(pid_t)) { |
diff --git a/sway/commands/floating.c b/sway/commands/floating.c index ce123345..74f6522c 100644 --- a/sway/commands/floating.c +++ b/sway/commands/floating.c | |||
@@ -40,8 +40,8 @@ struct cmd_results *cmd_floating(int argc, char **argv) { | |||
40 | // If the container is in a floating split container, | 40 | // If the container is in a floating split container, |
41 | // operate on the split container instead of the child. | 41 | // operate on the split container instead of the child. |
42 | if (container_is_floating_or_child(container)) { | 42 | if (container_is_floating_or_child(container)) { |
43 | while (container->parent) { | 43 | while (container->pending.parent) { |
44 | container = container->parent; | 44 | container = container->pending.parent; |
45 | } | 45 | } |
46 | } | 46 | } |
47 | 47 | ||
@@ -51,8 +51,8 @@ struct cmd_results *cmd_floating(int argc, char **argv) { | |||
51 | container_set_floating(container, wants_floating); | 51 | container_set_floating(container, wants_floating); |
52 | 52 | ||
53 | // Floating containers in the scratchpad should be ignored | 53 | // Floating containers in the scratchpad should be ignored |
54 | if (container->workspace) { | 54 | if (container->pending.workspace) { |
55 | arrange_workspace(container->workspace); | 55 | arrange_workspace(container->pending.workspace); |
56 | } | 56 | } |
57 | 57 | ||
58 | return cmd_results_new(CMD_SUCCESS, NULL); | 58 | return cmd_results_new(CMD_SUCCESS, NULL); |
diff --git a/sway/commands/focus.c b/sway/commands/focus.c index 79b7aed5..6771ca2f 100644 --- a/sway/commands/focus.c +++ b/sway/commands/focus.c | |||
@@ -141,9 +141,9 @@ static struct sway_node *node_get_in_direction_tiling( | |||
141 | struct sway_container *wrap_candidate = NULL; | 141 | struct sway_container *wrap_candidate = NULL; |
142 | struct sway_container *current = container; | 142 | struct sway_container *current = container; |
143 | while (current) { | 143 | while (current) { |
144 | if (current->fullscreen_mode == FULLSCREEN_WORKSPACE) { | 144 | if (current->pending.fullscreen_mode == FULLSCREEN_WORKSPACE) { |
145 | // Fullscreen container with a direction - go straight to outputs | 145 | // Fullscreen container with a direction - go straight to outputs |
146 | struct sway_output *output = current->workspace->output; | 146 | struct sway_output *output = current->pending.workspace->output; |
147 | struct sway_output *new_output = | 147 | struct sway_output *new_output = |
148 | output_get_in_direction(output, dir); | 148 | output_get_in_direction(output, dir); |
149 | if (!new_output) { | 149 | if (!new_output) { |
@@ -151,7 +151,7 @@ static struct sway_node *node_get_in_direction_tiling( | |||
151 | } | 151 | } |
152 | return get_node_in_output_direction(new_output, dir); | 152 | return get_node_in_output_direction(new_output, dir); |
153 | } | 153 | } |
154 | if (current->fullscreen_mode == FULLSCREEN_GLOBAL) { | 154 | if (current->pending.fullscreen_mode == FULLSCREEN_GLOBAL) { |
155 | return NULL; | 155 | return NULL; |
156 | } | 156 | } |
157 | 157 | ||
@@ -202,11 +202,11 @@ static struct sway_node *node_get_in_direction_tiling( | |||
202 | } | 202 | } |
203 | } | 203 | } |
204 | 204 | ||
205 | current = current->parent; | 205 | current = current->pending.parent; |
206 | } | 206 | } |
207 | 207 | ||
208 | // Check a different output | 208 | // Check a different output |
209 | struct sway_output *output = container->workspace->output; | 209 | struct sway_output *output = container->pending.workspace->output; |
210 | struct sway_output *new_output = output_get_in_direction(output, dir); | 210 | struct sway_output *new_output = output_get_in_direction(output, dir); |
211 | if ((config->focus_wrapping != WRAP_WORKSPACE || | 211 | if ((config->focus_wrapping != WRAP_WORKSPACE || |
212 | container->node.type == N_WORKSPACE) && new_output) { | 212 | container->node.type == N_WORKSPACE) && new_output) { |
@@ -226,23 +226,23 @@ static struct sway_node *node_get_in_direction_tiling( | |||
226 | static struct sway_node *node_get_in_direction_floating( | 226 | static struct sway_node *node_get_in_direction_floating( |
227 | struct sway_container *con, struct sway_seat *seat, | 227 | struct sway_container *con, struct sway_seat *seat, |
228 | enum wlr_direction dir) { | 228 | enum wlr_direction dir) { |
229 | double ref_lx = con->x + con->width / 2; | 229 | double ref_lx = con->pending.x + con->pending.width / 2; |
230 | double ref_ly = con->y + con->height / 2; | 230 | double ref_ly = con->pending.y + con->pending.height / 2; |
231 | double closest_distance = DBL_MAX; | 231 | double closest_distance = DBL_MAX; |
232 | struct sway_container *closest_con = NULL; | 232 | struct sway_container *closest_con = NULL; |
233 | 233 | ||
234 | if (!con->workspace) { | 234 | if (!con->pending.workspace) { |
235 | return NULL; | 235 | return NULL; |
236 | } | 236 | } |
237 | 237 | ||
238 | for (int i = 0; i < con->workspace->floating->length; i++) { | 238 | for (int i = 0; i < con->pending.workspace->floating->length; i++) { |
239 | struct sway_container *floater = con->workspace->floating->items[i]; | 239 | struct sway_container *floater = con->pending.workspace->floating->items[i]; |
240 | if (floater == con) { | 240 | if (floater == con) { |
241 | continue; | 241 | continue; |
242 | } | 242 | } |
243 | float distance = dir == WLR_DIRECTION_LEFT || dir == WLR_DIRECTION_RIGHT | 243 | float distance = dir == WLR_DIRECTION_LEFT || dir == WLR_DIRECTION_RIGHT |
244 | ? (floater->x + floater->width / 2) - ref_lx | 244 | ? (floater->pending.x + floater->pending.width / 2) - ref_lx |
245 | : (floater->y + floater->height / 2) - ref_ly; | 245 | : (floater->pending.y + floater->pending.height / 2) - ref_ly; |
246 | if (dir == WLR_DIRECTION_LEFT || dir == WLR_DIRECTION_UP) { | 246 | if (dir == WLR_DIRECTION_LEFT || dir == WLR_DIRECTION_UP) { |
247 | distance = -distance; | 247 | distance = -distance; |
248 | } | 248 | } |
@@ -334,7 +334,7 @@ static struct cmd_results *focus_output(struct sway_seat *seat, | |||
334 | static struct cmd_results *focus_parent(void) { | 334 | static struct cmd_results *focus_parent(void) { |
335 | struct sway_seat *seat = config->handler_context.seat; | 335 | struct sway_seat *seat = config->handler_context.seat; |
336 | struct sway_container *con = config->handler_context.container; | 336 | struct sway_container *con = config->handler_context.container; |
337 | if (!con || con->fullscreen_mode) { | 337 | if (!con || con->pending.fullscreen_mode) { |
338 | return cmd_results_new(CMD_SUCCESS, NULL); | 338 | return cmd_results_new(CMD_SUCCESS, NULL); |
339 | } | 339 | } |
340 | struct sway_node *parent = node_get_parent(&con->node); | 340 | struct sway_node *parent = node_get_parent(&con->node); |
@@ -377,6 +377,13 @@ struct cmd_results *cmd_focus(int argc, char **argv) { | |||
377 | if (container_is_scratchpad_hidden_or_child(container)) { | 377 | if (container_is_scratchpad_hidden_or_child(container)) { |
378 | root_scratchpad_show(container); | 378 | root_scratchpad_show(container); |
379 | } | 379 | } |
380 | // if we are switching to a container under a fullscreen window, we first | ||
381 | // need to exit fullscreen so that the newly focused container becomes visible | ||
382 | struct sway_container *obstructing = container_obstructing_fullscreen_container(container); | ||
383 | if (obstructing) { | ||
384 | container_fullscreen_disable(obstructing); | ||
385 | arrange_root(); | ||
386 | } | ||
380 | seat_set_focus_container(seat, container); | 387 | seat_set_focus_container(seat, container); |
381 | seat_consider_warp_to_focus(seat); | 388 | seat_consider_warp_to_focus(seat); |
382 | container_raise_floating(container); | 389 | container_raise_floating(container); |
diff --git a/sway/commands/font.c b/sway/commands/font.c index c54365b5..cea720f5 100644 --- a/sway/commands/font.c +++ b/sway/commands/font.c | |||
@@ -22,6 +22,6 @@ struct cmd_results *cmd_font(int argc, char **argv) { | |||
22 | } | 22 | } |
23 | 23 | ||
24 | free(font); | 24 | free(font); |
25 | config_update_font_height(true); | 25 | config_update_font_height(); |
26 | return cmd_results_new(CMD_SUCCESS, NULL); | 26 | return cmd_results_new(CMD_SUCCESS, NULL); |
27 | } | 27 | } |
diff --git a/sway/commands/fullscreen.c b/sway/commands/fullscreen.c index 3392a7f7..21c1e9a0 100644 --- a/sway/commands/fullscreen.c +++ b/sway/commands/fullscreen.c | |||
@@ -18,30 +18,19 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) { | |||
18 | return cmd_results_new(CMD_FAILURE, | 18 | return cmd_results_new(CMD_FAILURE, |
19 | "Can't run this command while there's no outputs connected."); | 19 | "Can't run this command while there's no outputs connected."); |
20 | } | 20 | } |
21 | struct sway_node *node = config->handler_context.node; | ||
22 | struct sway_container *container = config->handler_context.container; | 21 | struct sway_container *container = config->handler_context.container; |
23 | struct sway_workspace *workspace = config->handler_context.workspace; | ||
24 | if (node->type == N_WORKSPACE && workspace->tiling->length == 0) { | ||
25 | return cmd_results_new(CMD_FAILURE, | ||
26 | "Can't fullscreen an empty workspace"); | ||
27 | } | ||
28 | 22 | ||
29 | // If in the scratchpad, operate on the highest container | 23 | if (!container) { |
30 | if (container && !container->workspace) { | 24 | // If the focus is not a container, do nothing successfully |
31 | while (container->parent) { | 25 | return cmd_results_new(CMD_SUCCESS, NULL); |
32 | container = container->parent; | 26 | } else if (!container->pending.workspace) { |
33 | } | 27 | // If in the scratchpad, operate on the highest container |
34 | } | 28 | while (container->pending.parent) { |
35 | 29 | container = container->pending.parent; | |
36 | bool is_fullscreen = false; | ||
37 | for (struct sway_container *curr = container; curr; curr = curr->parent) { | ||
38 | if (curr->fullscreen_mode != FULLSCREEN_NONE) { | ||
39 | container = curr; | ||
40 | is_fullscreen = true; | ||
41 | break; | ||
42 | } | 30 | } |
43 | } | 31 | } |
44 | 32 | ||
33 | bool is_fullscreen = container->pending.fullscreen_mode != FULLSCREEN_NONE; | ||
45 | bool global = false; | 34 | bool global = false; |
46 | bool enable = !is_fullscreen; | 35 | bool enable = !is_fullscreen; |
47 | 36 | ||
@@ -57,13 +46,6 @@ struct cmd_results *cmd_fullscreen(int argc, char **argv) { | |||
57 | global = strcasecmp(argv[1], "global") == 0; | 46 | global = strcasecmp(argv[1], "global") == 0; |
58 | } | 47 | } |
59 | 48 | ||
60 | if (enable && node->type == N_WORKSPACE) { | ||
61 | // Wrap the workspace's children in a container so we can fullscreen it | ||
62 | container = workspace_wrap_children(workspace); | ||
63 | workspace->layout = L_HORIZ; | ||
64 | seat_set_focus_container(config->handler_context.seat, container); | ||
65 | } | ||
66 | |||
67 | enum sway_fullscreen_mode mode = FULLSCREEN_NONE; | 49 | enum sway_fullscreen_mode mode = FULLSCREEN_NONE; |
68 | if (enable) { | 50 | if (enable) { |
69 | mode = global ? FULLSCREEN_GLOBAL : FULLSCREEN_WORKSPACE; | 51 | mode = global ? FULLSCREEN_GLOBAL : FULLSCREEN_WORKSPACE; |
diff --git a/sway/commands/gaps.c b/sway/commands/gaps.c index 021df843..1deeb56e 100644 --- a/sway/commands/gaps.c +++ b/sway/commands/gaps.c | |||
@@ -11,7 +11,8 @@ | |||
11 | enum gaps_op { | 11 | enum gaps_op { |
12 | GAPS_OP_SET, | 12 | GAPS_OP_SET, |
13 | GAPS_OP_ADD, | 13 | GAPS_OP_ADD, |
14 | GAPS_OP_SUBTRACT | 14 | GAPS_OP_SUBTRACT, |
15 | GAPS_OP_TOGGLE | ||
15 | }; | 16 | }; |
16 | 17 | ||
17 | struct gaps_data { | 18 | struct gaps_data { |
@@ -102,6 +103,9 @@ static void apply_gaps_op(int *prop, enum gaps_op op, int amount) { | |||
102 | case GAPS_OP_SUBTRACT: | 103 | case GAPS_OP_SUBTRACT: |
103 | *prop -= amount; | 104 | *prop -= amount; |
104 | break; | 105 | break; |
106 | case GAPS_OP_TOGGLE: | ||
107 | *prop = *prop ? 0 : amount; | ||
108 | break; | ||
105 | } | 109 | } |
106 | } | 110 | } |
107 | 111 | ||
@@ -133,9 +137,9 @@ static void configure_gaps(struct sway_workspace *ws, void *_data) { | |||
133 | } | 137 | } |
134 | 138 | ||
135 | // gaps inner|outer|horizontal|vertical|top|right|bottom|left current|all | 139 | // gaps inner|outer|horizontal|vertical|top|right|bottom|left current|all |
136 | // set|plus|minus <px> | 140 | // set|plus|minus|toggle <px> |
137 | static const char expected_runtime[] = "'gaps inner|outer|horizontal|vertical|" | 141 | static const char expected_runtime[] = "'gaps inner|outer|horizontal|vertical|" |
138 | "top|right|bottom|left current|all set|plus|minus <px>'"; | 142 | "top|right|bottom|left current|all set|plus|minus|toggle <px>'"; |
139 | static struct cmd_results *gaps_set_runtime(int argc, char **argv) { | 143 | static struct cmd_results *gaps_set_runtime(int argc, char **argv) { |
140 | struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 4); | 144 | struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 4); |
141 | if (error) { | 145 | if (error) { |
@@ -180,6 +184,8 @@ static struct cmd_results *gaps_set_runtime(int argc, char **argv) { | |||
180 | data.operation = GAPS_OP_ADD; | 184 | data.operation = GAPS_OP_ADD; |
181 | } else if (strcasecmp(argv[2], "minus") == 0) { | 185 | } else if (strcasecmp(argv[2], "minus") == 0) { |
182 | data.operation = GAPS_OP_SUBTRACT; | 186 | data.operation = GAPS_OP_SUBTRACT; |
187 | } else if (strcasecmp(argv[2], "toggle") == 0) { | ||
188 | data.operation = GAPS_OP_TOGGLE; | ||
183 | } else { | 189 | } else { |
184 | return cmd_results_new(CMD_INVALID, "Expected %s", expected_runtime); | 190 | return cmd_results_new(CMD_INVALID, "Expected %s", expected_runtime); |
185 | } | 191 | } |
@@ -200,7 +206,7 @@ static struct cmd_results *gaps_set_runtime(int argc, char **argv) { | |||
200 | } | 206 | } |
201 | 207 | ||
202 | // gaps inner|outer|<dir>|<side> <px> - sets defaults for workspaces | 208 | // gaps inner|outer|<dir>|<side> <px> - sets defaults for workspaces |
203 | // gaps inner|outer|<dir>|<side> current|all set|plus|minus <px> - runtime only | 209 | // gaps inner|outer|<dir>|<side> current|all set|plus|minus|toggle <px> - runtime only |
204 | // <dir> = horizontal|vertical | 210 | // <dir> = horizontal|vertical |
205 | // <side> = top|right|bottom|left | 211 | // <side> = top|right|bottom|left |
206 | struct cmd_results *cmd_gaps(int argc, char **argv) { | 212 | struct cmd_results *cmd_gaps(int argc, char **argv) { |
diff --git a/sway/commands/input.c b/sway/commands/input.c index c9bb8e06..77acb671 100644 --- a/sway/commands/input.c +++ b/sway/commands/input.c | |||
@@ -7,7 +7,7 @@ | |||
7 | #include "stringop.h" | 7 | #include "stringop.h" |
8 | 8 | ||
9 | // must be in order for the bsearch | 9 | // must be in order for the bsearch |
10 | static struct cmd_handler input_handlers[] = { | 10 | static const struct cmd_handler input_handlers[] = { |
11 | { "accel_profile", input_cmd_accel_profile }, | 11 | { "accel_profile", input_cmd_accel_profile }, |
12 | { "calibration_matrix", input_cmd_calibration_matrix }, | 12 | { "calibration_matrix", input_cmd_calibration_matrix }, |
13 | { "click_method", input_cmd_click_method }, | 13 | { "click_method", input_cmd_click_method }, |
@@ -40,7 +40,7 @@ static struct cmd_handler input_handlers[] = { | |||
40 | }; | 40 | }; |
41 | 41 | ||
42 | // must be in order for the bsearch | 42 | // must be in order for the bsearch |
43 | static struct cmd_handler input_config_handlers[] = { | 43 | static const struct cmd_handler input_config_handlers[] = { |
44 | { "xkb_capslock", input_cmd_xkb_capslock }, | 44 | { "xkb_capslock", input_cmd_xkb_capslock }, |
45 | { "xkb_numlock", input_cmd_xkb_numlock }, | 45 | { "xkb_numlock", input_cmd_xkb_numlock }, |
46 | }; | 46 | }; |
diff --git a/sway/commands/input/map_to_region.c b/sway/commands/input/map_to_region.c index e85495e5..284b57d0 100644 --- a/sway/commands/input/map_to_region.c +++ b/sway/commands/input/map_to_region.c | |||
@@ -1,7 +1,6 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | 1 | #define _POSIX_C_SOURCE 200809L |
2 | #include <stdlib.h> | 2 | #include <stdlib.h> |
3 | #include <string.h> | 3 | #include <string.h> |
4 | #include <wlr/types/wlr_box.h> | ||
5 | #include "sway/commands.h" | 4 | #include "sway/commands.h" |
6 | #include "sway/config.h" | 5 | #include "sway/config.h" |
7 | 6 | ||
diff --git a/sway/commands/layout.c b/sway/commands/layout.c index f2af183b..2ba61b38 100644 --- a/sway/commands/layout.c +++ b/sway/commands/layout.c | |||
@@ -133,7 +133,7 @@ struct cmd_results *cmd_layout(int argc, char **argv) { | |||
133 | 133 | ||
134 | // Operate on parent container, like i3. | 134 | // Operate on parent container, like i3. |
135 | if (container) { | 135 | if (container) { |
136 | container = container->parent; | 136 | container = container->pending.parent; |
137 | } | 137 | } |
138 | 138 | ||
139 | // We could be working with a container OR a workspace. These are different | 139 | // 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) { | |||
142 | enum sway_container_layout new_layout = L_NONE; | 142 | enum sway_container_layout new_layout = L_NONE; |
143 | enum sway_container_layout old_layout = L_NONE; | 143 | enum sway_container_layout old_layout = L_NONE; |
144 | if (container) { | 144 | if (container) { |
145 | old_layout = container->layout; | 145 | old_layout = container->pending.layout; |
146 | new_layout = get_layout(argc, argv, | 146 | new_layout = get_layout(argc, argv, |
147 | container->layout, container->prev_split_layout, | 147 | container->pending.layout, container->prev_split_layout, |
148 | container->workspace->output); | 148 | container->pending.workspace->output); |
149 | } else { | 149 | } else { |
150 | old_layout = workspace->layout; | 150 | old_layout = workspace->layout; |
151 | new_layout = get_layout(argc, argv, | 151 | new_layout = get_layout(argc, argv, |
@@ -160,13 +160,13 @@ struct cmd_results *cmd_layout(int argc, char **argv) { | |||
160 | if (old_layout != L_TABBED && old_layout != L_STACKED) { | 160 | if (old_layout != L_TABBED && old_layout != L_STACKED) { |
161 | container->prev_split_layout = old_layout; | 161 | container->prev_split_layout = old_layout; |
162 | } | 162 | } |
163 | container->layout = new_layout; | 163 | container->pending.layout = new_layout; |
164 | container_update_representation(container); | 164 | container_update_representation(container); |
165 | } else if (config->handler_context.container) { | 165 | } else if (config->handler_context.container) { |
166 | // i3 avoids changing workspace layouts with a new container | 166 | // i3 avoids changing workspace layouts with a new container |
167 | // https://github.com/i3/i3/blob/3cd1c45eba6de073bc4300eebb4e1cc1a0c4479a/src/con.c#L1817 | 167 | // https://github.com/i3/i3/blob/3cd1c45eba6de073bc4300eebb4e1cc1a0c4479a/src/con.c#L1817 |
168 | container = workspace_wrap_children(workspace); | 168 | container = workspace_wrap_children(workspace); |
169 | container->layout = new_layout; | 169 | container->pending.layout = new_layout; |
170 | container_update_representation(container); | 170 | container_update_representation(container); |
171 | } else { | 171 | } else { |
172 | if (old_layout != L_TABBED && old_layout != L_STACKED) { | 172 | if (old_layout != L_TABBED && old_layout != L_STACKED) { |
diff --git a/sway/commands/mode.c b/sway/commands/mode.c index a5871dab..e23e4ee4 100644 --- a/sway/commands/mode.c +++ b/sway/commands/mode.c | |||
@@ -9,7 +9,7 @@ | |||
9 | #include "stringop.h" | 9 | #include "stringop.h" |
10 | 10 | ||
11 | // Must be in order for the bsearch | 11 | // Must be in order for the bsearch |
12 | static struct cmd_handler mode_handlers[] = { | 12 | static const struct cmd_handler mode_handlers[] = { |
13 | { "bindcode", cmd_bindcode }, | 13 | { "bindcode", cmd_bindcode }, |
14 | { "bindswitch", cmd_bindswitch }, | 14 | { "bindswitch", cmd_bindswitch }, |
15 | { "bindsym", cmd_bindsym }, | 15 | { "bindsym", cmd_bindsym }, |
diff --git a/sway/commands/move.c b/sway/commands/move.c index f8f89f18..f2702fa1 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c | |||
@@ -113,8 +113,8 @@ static void container_move_to_container_from_direction( | |||
113 | struct sway_container *container, struct sway_container *destination, | 113 | struct sway_container *container, struct sway_container *destination, |
114 | enum wlr_direction move_dir) { | 114 | enum wlr_direction move_dir) { |
115 | if (destination->view) { | 115 | if (destination->view) { |
116 | if (destination->parent == container->parent && | 116 | if (destination->pending.parent == container->pending.parent && |
117 | destination->workspace == container->workspace) { | 117 | destination->pending.workspace == container->pending.workspace) { |
118 | sway_log(SWAY_DEBUG, "Swapping siblings"); | 118 | sway_log(SWAY_DEBUG, "Swapping siblings"); |
119 | list_t *siblings = container_get_siblings(container); | 119 | list_t *siblings = container_get_siblings(container); |
120 | int container_index = list_find(siblings, container); | 120 | int container_index = list_find(siblings, container); |
@@ -126,28 +126,28 @@ static void container_move_to_container_from_direction( | |||
126 | int offset = | 126 | int offset = |
127 | move_dir == WLR_DIRECTION_LEFT || move_dir == WLR_DIRECTION_UP; | 127 | move_dir == WLR_DIRECTION_LEFT || move_dir == WLR_DIRECTION_UP; |
128 | int index = container_sibling_index(destination) + offset; | 128 | int index = container_sibling_index(destination) + offset; |
129 | if (destination->parent) { | 129 | if (destination->pending.parent) { |
130 | container_insert_child(destination->parent, container, index); | 130 | container_insert_child(destination->pending.parent, container, index); |
131 | } else { | 131 | } else { |
132 | workspace_insert_tiling(destination->workspace, | 132 | workspace_insert_tiling(destination->pending.workspace, |
133 | container, index); | 133 | container, index); |
134 | } | 134 | } |
135 | container->width = container->height = 0; | 135 | container->pending.width = container->pending.height = 0; |
136 | container->width_fraction = container->height_fraction = 0; | 136 | container->width_fraction = container->height_fraction = 0; |
137 | workspace_squash(destination->workspace); | 137 | workspace_squash(destination->pending.workspace); |
138 | } | 138 | } |
139 | return; | 139 | return; |
140 | } | 140 | } |
141 | 141 | ||
142 | if (is_parallel(destination->layout, move_dir)) { | 142 | if (is_parallel(destination->pending.layout, move_dir)) { |
143 | sway_log(SWAY_DEBUG, "Reparenting container (parallel)"); | 143 | sway_log(SWAY_DEBUG, "Reparenting container (parallel)"); |
144 | int index = | 144 | int index = |
145 | move_dir == WLR_DIRECTION_RIGHT || move_dir == WLR_DIRECTION_DOWN ? | 145 | move_dir == WLR_DIRECTION_RIGHT || move_dir == WLR_DIRECTION_DOWN ? |
146 | 0 : destination->children->length; | 146 | 0 : destination->pending.children->length; |
147 | container_insert_child(destination, container, index); | 147 | container_insert_child(destination, container, index); |
148 | container->width = container->height = 0; | 148 | container->pending.width = container->pending.height = 0; |
149 | container->width_fraction = container->height_fraction = 0; | 149 | container->width_fraction = container->height_fraction = 0; |
150 | workspace_squash(destination->workspace); | 150 | workspace_squash(destination->pending.workspace); |
151 | return; | 151 | return; |
152 | } | 152 | } |
153 | 153 | ||
@@ -168,7 +168,7 @@ static void container_move_to_container_from_direction( | |||
168 | static void container_move_to_workspace_from_direction( | 168 | static void container_move_to_workspace_from_direction( |
169 | struct sway_container *container, struct sway_workspace *workspace, | 169 | struct sway_container *container, struct sway_workspace *workspace, |
170 | enum wlr_direction move_dir) { | 170 | enum wlr_direction move_dir) { |
171 | container->width = container->height = 0; | 171 | container->pending.width = container->pending.height = 0; |
172 | container->width_fraction = container->height_fraction = 0; | 172 | container->width_fraction = container->height_fraction = 0; |
173 | 173 | ||
174 | if (is_parallel(workspace->layout, move_dir)) { | 174 | if (is_parallel(workspace->layout, move_dir)) { |
@@ -188,8 +188,8 @@ static void container_move_to_workspace_from_direction( | |||
188 | workspace_add_tiling(workspace, container); | 188 | workspace_add_tiling(workspace, container); |
189 | return; | 189 | return; |
190 | } | 190 | } |
191 | while (focus_inactive->parent) { | 191 | while (focus_inactive->pending.parent) { |
192 | focus_inactive = focus_inactive->parent; | 192 | focus_inactive = focus_inactive->pending.parent; |
193 | } | 193 | } |
194 | container_move_to_container_from_direction(container, focus_inactive, | 194 | container_move_to_container_from_direction(container, focus_inactive, |
195 | move_dir); | 195 | move_dir); |
@@ -197,25 +197,25 @@ static void container_move_to_workspace_from_direction( | |||
197 | 197 | ||
198 | static void container_move_to_workspace(struct sway_container *container, | 198 | static void container_move_to_workspace(struct sway_container *container, |
199 | struct sway_workspace *workspace) { | 199 | struct sway_workspace *workspace) { |
200 | if (container->workspace == workspace) { | 200 | if (container->pending.workspace == workspace) { |
201 | return; | 201 | return; |
202 | } | 202 | } |
203 | struct sway_workspace *old_workspace = container->workspace; | 203 | struct sway_workspace *old_workspace = container->pending.workspace; |
204 | if (container_is_floating(container)) { | 204 | if (container_is_floating(container)) { |
205 | struct sway_output *old_output = container->workspace->output; | 205 | struct sway_output *old_output = container->pending.workspace->output; |
206 | container_detach(container); | 206 | container_detach(container); |
207 | workspace_add_floating(workspace, container); | 207 | workspace_add_floating(workspace, container); |
208 | container_handle_fullscreen_reparent(container); | 208 | container_handle_fullscreen_reparent(container); |
209 | // If changing output, center it within the workspace | 209 | // If changing output, center it within the workspace |
210 | if (old_output != workspace->output && !container->fullscreen_mode) { | 210 | if (old_output != workspace->output && !container->pending.fullscreen_mode) { |
211 | container_floating_move_to_center(container); | 211 | container_floating_move_to_center(container); |
212 | } | 212 | } |
213 | } else { | 213 | } else { |
214 | container_detach(container); | 214 | container_detach(container); |
215 | if (workspace_is_empty(workspace) && container->children) { | 215 | if (workspace_is_empty(workspace) && container->pending.children) { |
216 | workspace_unwrap_children(workspace, container); | 216 | workspace_unwrap_children(workspace, container); |
217 | } else { | 217 | } else { |
218 | container->width = container->height = 0; | 218 | container->pending.width = container->pending.height = 0; |
219 | container->width_fraction = container->height_fraction = 0; | 219 | container->width_fraction = container->height_fraction = 0; |
220 | workspace_add_tiling(workspace, container); | 220 | workspace_add_tiling(workspace, container); |
221 | } | 221 | } |
@@ -237,13 +237,13 @@ static void container_move_to_container(struct sway_container *container, | |||
237 | return; | 237 | return; |
238 | } | 238 | } |
239 | if (container_is_floating(container)) { | 239 | if (container_is_floating(container)) { |
240 | container_move_to_workspace(container, destination->workspace); | 240 | container_move_to_workspace(container, destination->pending.workspace); |
241 | return; | 241 | return; |
242 | } | 242 | } |
243 | struct sway_workspace *old_workspace = container->workspace; | 243 | struct sway_workspace *old_workspace = container->pending.workspace; |
244 | 244 | ||
245 | container_detach(container); | 245 | container_detach(container); |
246 | container->width = container->height = 0; | 246 | container->pending.width = container->pending.height = 0; |
247 | container->width_fraction = container->height_fraction = 0; | 247 | container->width_fraction = container->height_fraction = 0; |
248 | 248 | ||
249 | if (destination->view) { | 249 | if (destination->view) { |
@@ -256,12 +256,12 @@ static void container_move_to_container(struct sway_container *container, | |||
256 | ipc_event_window(container, "move"); | 256 | ipc_event_window(container, "move"); |
257 | } | 257 | } |
258 | 258 | ||
259 | if (destination->workspace) { | 259 | if (destination->pending.workspace) { |
260 | workspace_focus_fullscreen(destination->workspace); | 260 | workspace_focus_fullscreen(destination->pending.workspace); |
261 | workspace_detect_urgent(destination->workspace); | 261 | workspace_detect_urgent(destination->pending.workspace); |
262 | } | 262 | } |
263 | 263 | ||
264 | if (old_workspace && old_workspace != destination->workspace) { | 264 | if (old_workspace && old_workspace != destination->pending.workspace) { |
265 | workspace_detect_urgent(old_workspace); | 265 | workspace_detect_urgent(old_workspace); |
266 | } | 266 | } |
267 | } | 267 | } |
@@ -275,7 +275,7 @@ static bool container_move_to_next_output(struct sway_container *container, | |||
275 | if (!sway_assert(ws, "Expected output to have a workspace")) { | 275 | if (!sway_assert(ws, "Expected output to have a workspace")) { |
276 | return false; | 276 | return false; |
277 | } | 277 | } |
278 | switch (container->fullscreen_mode) { | 278 | switch (container->pending.fullscreen_mode) { |
279 | case FULLSCREEN_NONE: | 279 | case FULLSCREEN_NONE: |
280 | container_move_to_workspace_from_direction(container, ws, move_dir); | 280 | container_move_to_workspace_from_direction(container, ws, move_dir); |
281 | return true; | 281 | return true; |
@@ -293,12 +293,12 @@ static bool container_move_to_next_output(struct sway_container *container, | |||
293 | static bool container_move_in_direction(struct sway_container *container, | 293 | static bool container_move_in_direction(struct sway_container *container, |
294 | enum wlr_direction move_dir) { | 294 | enum wlr_direction move_dir) { |
295 | // If moving a fullscreen view, only consider outputs | 295 | // If moving a fullscreen view, only consider outputs |
296 | switch (container->fullscreen_mode) { | 296 | switch (container->pending.fullscreen_mode) { |
297 | case FULLSCREEN_NONE: | 297 | case FULLSCREEN_NONE: |
298 | break; | 298 | break; |
299 | case FULLSCREEN_WORKSPACE: | 299 | case FULLSCREEN_WORKSPACE: |
300 | return container_move_to_next_output(container, | 300 | return container_move_to_next_output(container, |
301 | container->workspace->output, move_dir); | 301 | container->pending.workspace->output, move_dir); |
302 | case FULLSCREEN_GLOBAL: | 302 | case FULLSCREEN_GLOBAL: |
303 | return false; | 303 | return false; |
304 | } | 304 | } |
@@ -317,26 +317,26 @@ static bool container_move_in_direction(struct sway_container *container, | |||
317 | while (!ancestor) { | 317 | while (!ancestor) { |
318 | // Don't allow containers to move out of their | 318 | // Don't allow containers to move out of their |
319 | // fullscreen or floating parent | 319 | // fullscreen or floating parent |
320 | if (current->fullscreen_mode || container_is_floating(current)) { | 320 | if (current->pending.fullscreen_mode || container_is_floating(current)) { |
321 | return false; | 321 | return false; |
322 | } | 322 | } |
323 | 323 | ||
324 | enum sway_container_layout parent_layout = container_parent_layout(current); | 324 | enum sway_container_layout parent_layout = container_parent_layout(current); |
325 | if (!is_parallel(parent_layout, move_dir)) { | 325 | if (!is_parallel(parent_layout, move_dir)) { |
326 | if (!current->parent) { | 326 | if (!current->pending.parent) { |
327 | // No parallel parent, so we reorient the workspace | 327 | // No parallel parent, so we reorient the workspace |
328 | current = workspace_wrap_children(current->workspace); | 328 | current = workspace_wrap_children(current->pending.workspace); |
329 | current->workspace->layout = | 329 | current->pending.workspace->layout = |
330 | move_dir == WLR_DIRECTION_LEFT || | 330 | move_dir == WLR_DIRECTION_LEFT || |
331 | move_dir == WLR_DIRECTION_RIGHT ? | 331 | move_dir == WLR_DIRECTION_RIGHT ? |
332 | L_HORIZ : L_VERT; | 332 | L_HORIZ : L_VERT; |
333 | container->height = container->width = 0; | 333 | container->pending.height = container->pending.width = 0; |
334 | container->height_fraction = container->width_fraction = 0; | 334 | container->height_fraction = container->width_fraction = 0; |
335 | workspace_update_representation(current->workspace); | 335 | workspace_update_representation(current->pending.workspace); |
336 | wrapped = true; | 336 | wrapped = true; |
337 | } else { | 337 | } else { |
338 | // Keep looking for a parallel parent | 338 | // Keep looking for a parallel parent |
339 | current = current->parent; | 339 | current = current->pending.parent; |
340 | } | 340 | } |
341 | continue; | 341 | continue; |
342 | } | 342 | } |
@@ -356,14 +356,14 @@ static bool container_move_in_direction(struct sway_container *container, | |||
356 | container_move_to_container_from_direction(container, | 356 | container_move_to_container_from_direction(container, |
357 | target, move_dir); | 357 | target, move_dir); |
358 | return true; | 358 | return true; |
359 | } else if (!container->parent) { | 359 | } else if (!container->pending.parent) { |
360 | // Container is at workspace level so we move it to the | 360 | // Container is at workspace level so we move it to the |
361 | // next workspace if possible | 361 | // next workspace if possible |
362 | return container_move_to_next_output(container, | 362 | return container_move_to_next_output(container, |
363 | current->workspace->output, move_dir); | 363 | current->pending.workspace->output, move_dir); |
364 | } else { | 364 | } else { |
365 | // Container has escaped its immediate parallel parent | 365 | // Container has escaped its immediate parallel parent |
366 | current = current->parent; | 366 | current = current->pending.parent; |
367 | continue; | 367 | continue; |
368 | } | 368 | } |
369 | } | 369 | } |
@@ -377,31 +377,31 @@ static bool container_move_in_direction(struct sway_container *container, | |||
377 | container_move_to_container_from_direction(container, | 377 | container_move_to_container_from_direction(container, |
378 | target, move_dir); | 378 | target, move_dir); |
379 | return true; | 379 | return true; |
380 | } else if (!wrapped && !container->parent->parent && | 380 | } else if (!wrapped && !container->pending.parent->pending.parent && |
381 | container->parent->children->length == 1) { | 381 | container->pending.parent->pending.children->length == 1) { |
382 | // Treat singleton children as if they are at workspace level like i3 | 382 | // Treat singleton children as if they are at workspace level like i3 |
383 | // https://github.com/i3/i3/blob/1d9160f2d247dbaa83fb62f02fd7041dec767fc2/src/move.c#L367 | 383 | // https://github.com/i3/i3/blob/1d9160f2d247dbaa83fb62f02fd7041dec767fc2/src/move.c#L367 |
384 | return container_move_to_next_output(container, | 384 | return container_move_to_next_output(container, |
385 | ancestor->workspace->output, move_dir); | 385 | ancestor->pending.workspace->output, move_dir); |
386 | } else { | 386 | } else { |
387 | // Container will be promoted | 387 | // Container will be promoted |
388 | struct sway_container *old_parent = container->parent; | 388 | struct sway_container *old_parent = container->pending.parent; |
389 | if (ancestor->parent) { | 389 | if (ancestor->pending.parent) { |
390 | // Container will move in with its parent | 390 | // Container will move in with its parent |
391 | container_insert_child(ancestor->parent, container, | 391 | container_insert_child(ancestor->pending.parent, container, |
392 | index + (offs < 0 ? 0 : 1)); | 392 | index + (offs < 0 ? 0 : 1)); |
393 | } else { | 393 | } else { |
394 | // Container will move to workspace level, | 394 | // Container will move to workspace level, |
395 | // may be re-split by workspace_layout | 395 | // may be re-split by workspace_layout |
396 | workspace_insert_tiling(ancestor->workspace, container, | 396 | workspace_insert_tiling(ancestor->pending.workspace, container, |
397 | index + (offs < 0 ? 0 : 1)); | 397 | index + (offs < 0 ? 0 : 1)); |
398 | } | 398 | } |
399 | ancestor->height = ancestor->width = 0; | 399 | ancestor->pending.height = ancestor->pending.width = 0; |
400 | ancestor->height_fraction = ancestor->width_fraction = 0; | 400 | ancestor->height_fraction = ancestor->width_fraction = 0; |
401 | if (old_parent) { | 401 | if (old_parent) { |
402 | container_reap_empty(old_parent); | 402 | container_reap_empty(old_parent); |
403 | } | 403 | } |
404 | workspace_squash(container->workspace); | 404 | workspace_squash(container->pending.workspace); |
405 | return true; | 405 | return true; |
406 | } | 406 | } |
407 | } | 407 | } |
@@ -427,14 +427,14 @@ static struct cmd_results *cmd_move_container(bool no_auto_back_and_forth, | |||
427 | container = workspace_wrap_children(workspace); | 427 | container = workspace_wrap_children(workspace); |
428 | } | 428 | } |
429 | 429 | ||
430 | if (container->fullscreen_mode == FULLSCREEN_GLOBAL) { | 430 | if (container->pending.fullscreen_mode == FULLSCREEN_GLOBAL) { |
431 | return cmd_results_new(CMD_FAILURE, | 431 | return cmd_results_new(CMD_FAILURE, |
432 | "Can't move fullscreen global container"); | 432 | "Can't move fullscreen global container"); |
433 | } | 433 | } |
434 | 434 | ||
435 | struct sway_seat *seat = config->handler_context.seat; | 435 | struct sway_seat *seat = config->handler_context.seat; |
436 | struct sway_container *old_parent = container->parent; | 436 | struct sway_container *old_parent = container->pending.parent; |
437 | struct sway_workspace *old_ws = container->workspace; | 437 | struct sway_workspace *old_ws = container->pending.workspace; |
438 | struct sway_output *old_output = old_ws ? old_ws->output : NULL; | 438 | struct sway_output *old_output = old_ws ? old_ws->output : NULL; |
439 | struct sway_node *destination = NULL; | 439 | struct sway_node *destination = NULL; |
440 | 440 | ||
@@ -508,7 +508,7 @@ static struct cmd_results *cmd_move_container(bool no_auto_back_and_forth, | |||
508 | destination = dst ? &dst->node : &ws->node; | 508 | destination = dst ? &dst->node : &ws->node; |
509 | } else if (strcasecmp(argv[0], "output") == 0) { | 509 | } else if (strcasecmp(argv[0], "output") == 0) { |
510 | struct sway_output *new_output = output_in_direction(argv[1], | 510 | struct sway_output *new_output = output_in_direction(argv[1], |
511 | old_output, container->x, container->y); | 511 | old_output, container->pending.x, container->pending.y); |
512 | if (!new_output) { | 512 | if (!new_output) { |
513 | return cmd_results_new(CMD_FAILURE, | 513 | return cmd_results_new(CMD_FAILURE, |
514 | "Can't find output with name/direction '%s'", argv[1]); | 514 | "Can't find output with name/direction '%s'", argv[1]); |
@@ -706,12 +706,12 @@ static struct cmd_results *cmd_move_in_direction( | |||
706 | "Cannot move workspaces in a direction"); | 706 | "Cannot move workspaces in a direction"); |
707 | } | 707 | } |
708 | if (container_is_floating(container)) { | 708 | if (container_is_floating(container)) { |
709 | if (container->fullscreen_mode) { | 709 | if (container->pending.fullscreen_mode) { |
710 | return cmd_results_new(CMD_FAILURE, | 710 | return cmd_results_new(CMD_FAILURE, |
711 | "Cannot move fullscreen floating container"); | 711 | "Cannot move fullscreen floating container"); |
712 | } | 712 | } |
713 | double lx = container->x; | 713 | double lx = container->pending.x; |
714 | double ly = container->y; | 714 | double ly = container->pending.y; |
715 | switch (direction) { | 715 | switch (direction) { |
716 | case WLR_DIRECTION_LEFT: | 716 | case WLR_DIRECTION_LEFT: |
717 | lx -= move_amt; | 717 | lx -= move_amt; |
@@ -729,8 +729,8 @@ static struct cmd_results *cmd_move_in_direction( | |||
729 | container_floating_move_to(container, lx, ly); | 729 | container_floating_move_to(container, lx, ly); |
730 | return cmd_results_new(CMD_SUCCESS, NULL); | 730 | return cmd_results_new(CMD_SUCCESS, NULL); |
731 | } | 731 | } |
732 | struct sway_workspace *old_ws = container->workspace; | 732 | struct sway_workspace *old_ws = container->pending.workspace; |
733 | struct sway_container *old_parent = container->parent; | 733 | struct sway_container *old_parent = container->pending.parent; |
734 | 734 | ||
735 | if (!container_move_in_direction(container, direction)) { | 735 | if (!container_move_in_direction(container, direction)) { |
736 | // Container didn't move | 736 | // Container didn't move |
@@ -744,7 +744,7 @@ static struct cmd_results *cmd_move_in_direction( | |||
744 | workspace_consider_destroy(old_ws); | 744 | workspace_consider_destroy(old_ws); |
745 | } | 745 | } |
746 | 746 | ||
747 | struct sway_workspace *new_ws = container->workspace; | 747 | struct sway_workspace *new_ws = container->pending.workspace; |
748 | 748 | ||
749 | if (root->fullscreen_global) { | 749 | if (root->fullscreen_global) { |
750 | arrange_root(); | 750 | arrange_root(); |
@@ -781,8 +781,8 @@ static struct cmd_results *cmd_move_to_position_pointer( | |||
781 | } | 781 | } |
782 | struct wlr_cursor *cursor = seat->cursor->cursor; | 782 | struct wlr_cursor *cursor = seat->cursor->cursor; |
783 | /* Determine where to put the window. */ | 783 | /* Determine where to put the window. */ |
784 | double lx = cursor->x - container->width / 2; | 784 | double lx = cursor->x - container->pending.width / 2; |
785 | double ly = cursor->y - container->height / 2; | 785 | double ly = cursor->y - container->pending.height / 2; |
786 | 786 | ||
787 | /* Correct target coordinates to be in bounds (on screen). */ | 787 | /* Correct target coordinates to be in bounds (on screen). */ |
788 | struct wlr_output *output = wlr_output_layout_output_at( | 788 | struct wlr_output *output = wlr_output_layout_output_at( |
@@ -792,11 +792,11 @@ static struct cmd_results *cmd_move_to_position_pointer( | |||
792 | wlr_output_layout_get_box(root->output_layout, output); | 792 | wlr_output_layout_get_box(root->output_layout, output); |
793 | lx = fmax(lx, box->x); | 793 | lx = fmax(lx, box->x); |
794 | ly = fmax(ly, box->y); | 794 | ly = fmax(ly, box->y); |
795 | if (lx + container->width > box->x + box->width) { | 795 | if (lx + container->pending.width > box->x + box->width) { |
796 | lx = box->x + box->width - container->width; | 796 | lx = box->x + box->width - container->pending.width; |
797 | } | 797 | } |
798 | if (ly + container->height > box->y + box->height) { | 798 | if (ly + container->pending.height > box->y + box->height) { |
799 | ly = box->y + box->height - container->height; | 799 | ly = box->y + box->height - container->pending.height; |
800 | } | 800 | } |
801 | } | 801 | } |
802 | 802 | ||
@@ -846,16 +846,16 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) { | |||
846 | } else if (strcmp(argv[0], "center") == 0) { | 846 | } else if (strcmp(argv[0], "center") == 0) { |
847 | double lx, ly; | 847 | double lx, ly; |
848 | if (absolute) { | 848 | if (absolute) { |
849 | lx = root->x + (root->width - container->width) / 2; | 849 | lx = root->x + (root->width - container->pending.width) / 2; |
850 | ly = root->y + (root->height - container->height) / 2; | 850 | ly = root->y + (root->height - container->pending.height) / 2; |
851 | } else { | 851 | } else { |
852 | struct sway_workspace *ws = container->workspace; | 852 | struct sway_workspace *ws = container->pending.workspace; |
853 | if (!ws) { | 853 | if (!ws) { |
854 | struct sway_seat *seat = config->handler_context.seat; | 854 | struct sway_seat *seat = config->handler_context.seat; |
855 | ws = seat_get_focused_workspace(seat); | 855 | ws = seat_get_focused_workspace(seat); |
856 | } | 856 | } |
857 | lx = ws->x + (ws->width - container->width) / 2; | 857 | lx = ws->x + (ws->width - container->pending.width) / 2; |
858 | ly = ws->y + (ws->height - container->height) / 2; | 858 | ly = ws->y + (ws->height - container->pending.height) / 2; |
859 | } | 859 | } |
860 | container_floating_move_to(container, lx, ly); | 860 | container_floating_move_to(container, lx, ly); |
861 | return cmd_results_new(CMD_SUCCESS, NULL); | 861 | return cmd_results_new(CMD_SUCCESS, NULL); |
@@ -886,7 +886,7 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) { | |||
886 | return cmd_results_new(CMD_INVALID, "Invalid y position specified"); | 886 | return cmd_results_new(CMD_INVALID, "Invalid y position specified"); |
887 | } | 887 | } |
888 | 888 | ||
889 | struct sway_workspace *ws = container->workspace; | 889 | struct sway_workspace *ws = container->pending.workspace; |
890 | if (!ws) { | 890 | if (!ws) { |
891 | struct sway_seat *seat = config->handler_context.seat; | 891 | struct sway_seat *seat = config->handler_context.seat; |
892 | ws = seat_get_focused_workspace(seat); | 892 | ws = seat_get_focused_workspace(seat); |
@@ -960,14 +960,14 @@ static struct cmd_results *cmd_move_to_scratchpad(void) { | |||
960 | // If the container is in a floating split container, | 960 | // If the container is in a floating split container, |
961 | // operate on the split container instead of the child. | 961 | // operate on the split container instead of the child. |
962 | if (container_is_floating_or_child(con)) { | 962 | if (container_is_floating_or_child(con)) { |
963 | while (con->parent) { | 963 | while (con->pending.parent) { |
964 | con = con->parent; | 964 | con = con->pending.parent; |
965 | } | 965 | } |
966 | } | 966 | } |
967 | 967 | ||
968 | if (!con->scratchpad) { | 968 | if (!con->scratchpad) { |
969 | root_scratchpad_add_container(con, NULL); | 969 | root_scratchpad_add_container(con, NULL); |
970 | } else if (con->workspace) { | 970 | } else if (con->pending.workspace) { |
971 | root_scratchpad_hide(con); | 971 | root_scratchpad_hide(con); |
972 | } | 972 | } |
973 | return cmd_results_new(CMD_SUCCESS, NULL); | 973 | return cmd_results_new(CMD_SUCCESS, NULL); |
diff --git a/sway/commands/output.c b/sway/commands/output.c index 5186a2ba..d8ef2885 100644 --- a/sway/commands/output.c +++ b/sway/commands/output.c | |||
@@ -6,7 +6,7 @@ | |||
6 | #include "log.h" | 6 | #include "log.h" |
7 | 7 | ||
8 | // must be in order for the bsearch | 8 | // must be in order for the bsearch |
9 | static struct cmd_handler output_handlers[] = { | 9 | static const struct cmd_handler output_handlers[] = { |
10 | { "adaptive_sync", output_cmd_adaptive_sync }, | 10 | { "adaptive_sync", output_cmd_adaptive_sync }, |
11 | { "background", output_cmd_background }, | 11 | { "background", output_cmd_background }, |
12 | { "bg", output_cmd_background }, | 12 | { "bg", output_cmd_background }, |
@@ -15,6 +15,7 @@ static struct cmd_handler output_handlers[] = { | |||
15 | { "enable", output_cmd_enable }, | 15 | { "enable", output_cmd_enable }, |
16 | { "max_render_time", output_cmd_max_render_time }, | 16 | { "max_render_time", output_cmd_max_render_time }, |
17 | { "mode", output_cmd_mode }, | 17 | { "mode", output_cmd_mode }, |
18 | { "modeline", output_cmd_modeline }, | ||
18 | { "pos", output_cmd_position }, | 19 | { "pos", output_cmd_position }, |
19 | { "position", output_cmd_position }, | 20 | { "position", output_cmd_position }, |
20 | { "res", output_cmd_mode }, | 21 | { "res", output_cmd_mode }, |
diff --git a/sway/commands/output/dpms.c b/sway/commands/output/dpms.c index 9d75a80e..638c0ade 100644 --- a/sway/commands/output/dpms.c +++ b/sway/commands/output/dpms.c | |||
@@ -1,6 +1,8 @@ | |||
1 | #include "sway/commands.h" | 1 | #include "sway/commands.h" |
2 | #include "sway/config.h" | 2 | #include "sway/config.h" |
3 | #include "sway/output.h" | ||
3 | #include "util.h" | 4 | #include "util.h" |
5 | #include <strings.h> | ||
4 | 6 | ||
5 | struct cmd_results *output_cmd_dpms(int argc, char **argv) { | 7 | struct cmd_results *output_cmd_dpms(int argc, char **argv) { |
6 | if (!config->handler_context.output_config) { | 8 | if (!config->handler_context.output_config) { |
@@ -10,7 +12,28 @@ struct cmd_results *output_cmd_dpms(int argc, char **argv) { | |||
10 | return cmd_results_new(CMD_INVALID, "Missing dpms argument."); | 12 | return cmd_results_new(CMD_INVALID, "Missing dpms argument."); |
11 | } | 13 | } |
12 | 14 | ||
13 | if (parse_boolean(argv[0], true)) { | 15 | enum config_dpms current_dpms = DPMS_ON; |
16 | |||
17 | if (strcasecmp(argv[0], "toggle") == 0) { | ||
18 | |||
19 | const char *oc_name = config->handler_context.output_config->name; | ||
20 | if (strcmp(oc_name, "*") == 0) { | ||
21 | return cmd_results_new(CMD_INVALID, | ||
22 | "Cannot apply toggle to all outputs."); | ||
23 | } | ||
24 | |||
25 | struct sway_output *sway_output = all_output_by_name_or_id(oc_name); | ||
26 | if (!sway_output || !sway_output->wlr_output) { | ||
27 | return cmd_results_new(CMD_FAILURE, | ||
28 | "Cannot apply toggle to unknown output %s", oc_name); | ||
29 | } | ||
30 | |||
31 | if (sway_output->enabled && !sway_output->wlr_output->enabled) { | ||
32 | current_dpms = DPMS_OFF; | ||
33 | } | ||
34 | } | ||
35 | |||
36 | if (parse_boolean(argv[0], current_dpms == DPMS_ON)) { | ||
14 | config->handler_context.output_config->dpms_state = DPMS_ON; | 37 | config->handler_context.output_config->dpms_state = DPMS_ON; |
15 | } else { | 38 | } else { |
16 | config->handler_context.output_config->dpms_state = DPMS_OFF; | 39 | config->handler_context.output_config->dpms_state = DPMS_OFF; |
diff --git a/sway/commands/output/mode.c b/sway/commands/output/mode.c index 5b710713..019d625a 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) { | |||
20 | output->custom_mode = 0; | 20 | output->custom_mode = 0; |
21 | } | 21 | } |
22 | 22 | ||
23 | // Reset custom modeline, if any | ||
24 | output->drm_mode.type = 0; | ||
25 | |||
23 | char *end; | 26 | char *end; |
24 | output->width = strtol(*argv, &end, 10); | 27 | output->width = strtol(*argv, &end, 10); |
25 | if (*end) { | 28 | if (*end) { |
@@ -58,3 +61,58 @@ struct cmd_results *output_cmd_mode(int argc, char **argv) { | |||
58 | return NULL; | 61 | return NULL; |
59 | } | 62 | } |
60 | 63 | ||
64 | static bool parse_modeline(char **argv, drmModeModeInfo *mode) { | ||
65 | mode->type = DRM_MODE_TYPE_USERDEF; | ||
66 | mode->clock = strtof(argv[0], NULL) * 1000; | ||
67 | mode->hdisplay = strtol(argv[1], NULL, 10); | ||
68 | mode->hsync_start = strtol(argv[2], NULL, 10); | ||
69 | mode->hsync_end = strtol(argv[3], NULL, 10); | ||
70 | mode->htotal = strtol(argv[4], NULL, 10); | ||
71 | mode->vdisplay = strtol(argv[5], NULL, 10); | ||
72 | mode->vsync_start = strtol(argv[6], NULL, 10); | ||
73 | mode->vsync_end = strtol(argv[7], NULL, 10); | ||
74 | mode->vtotal = strtol(argv[8], NULL, 10); | ||
75 | |||
76 | mode->vrefresh = mode->clock * 1000.0 * 1000.0 | ||
77 | / mode->htotal / mode->vtotal; | ||
78 | if (strcasecmp(argv[9], "+hsync") == 0) { | ||
79 | mode->flags |= DRM_MODE_FLAG_PHSYNC; | ||
80 | } else if (strcasecmp(argv[9], "-hsync") == 0) { | ||
81 | mode->flags |= DRM_MODE_FLAG_NHSYNC; | ||
82 | } else { | ||
83 | return false; | ||
84 | } | ||
85 | |||
86 | if (strcasecmp(argv[10], "+vsync") == 0) { | ||
87 | mode->flags |= DRM_MODE_FLAG_PVSYNC; | ||
88 | } else if (strcasecmp(argv[10], "-vsync") == 0) { | ||
89 | mode->flags |= DRM_MODE_FLAG_NVSYNC; | ||
90 | } else { | ||
91 | return false; | ||
92 | } | ||
93 | |||
94 | snprintf(mode->name, sizeof(mode->name), "%dx%d@%d", | ||
95 | mode->hdisplay, mode->vdisplay, mode->vrefresh / 1000); | ||
96 | |||
97 | return true; | ||
98 | } | ||
99 | |||
100 | struct cmd_results *output_cmd_modeline(int argc, char **argv) { | ||
101 | if (!config->handler_context.output_config) { | ||
102 | return cmd_results_new(CMD_FAILURE, "Missing output config"); | ||
103 | } | ||
104 | if (!argc) { | ||
105 | return cmd_results_new(CMD_INVALID, "Missing modeline argument."); | ||
106 | } | ||
107 | |||
108 | struct output_config *output = config->handler_context.output_config; | ||
109 | |||
110 | if (argc != 11 || !parse_modeline(argv, &output->drm_mode)) { | ||
111 | return cmd_results_new(CMD_INVALID, "Invalid modeline"); | ||
112 | } | ||
113 | |||
114 | config->handler_context.leftovers.argc = argc - 12; | ||
115 | config->handler_context.leftovers.argv = argv + 12; | ||
116 | return NULL; | ||
117 | } | ||
118 | |||
diff --git a/sway/commands/reload.c b/sway/commands/reload.c index 3c994d54..76f14bba 100644 --- a/sway/commands/reload.c +++ b/sway/commands/reload.c | |||
@@ -48,7 +48,6 @@ static void do_reload(void *data) { | |||
48 | } | 48 | } |
49 | list_free_items_and_destroy(bar_ids); | 49 | list_free_items_and_destroy(bar_ids); |
50 | 50 | ||
51 | config_update_font_height(true); | ||
52 | root_for_each_container(rebuild_textures_iterator, NULL); | 51 | root_for_each_container(rebuild_textures_iterator, NULL); |
53 | 52 | ||
54 | arrange_root(); | 53 | arrange_root(); |
diff --git a/sway/commands/resize.c b/sway/commands/resize.c index ca36e858..425069de 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, | |||
57 | (allow_last || index < siblings->length - 1)) { | 57 | (allow_last || index < siblings->length - 1)) { |
58 | return con; | 58 | return con; |
59 | } | 59 | } |
60 | con = con->parent; | 60 | con = con->pending.parent; |
61 | } | 61 | } |
62 | 62 | ||
63 | return NULL; | 63 | return NULL; |
@@ -115,13 +115,13 @@ void container_resize_tiled(struct sway_container *con, | |||
115 | int sibling_amount = prev ? ceil((double)amount / 2.0) : amount; | 115 | int sibling_amount = prev ? ceil((double)amount / 2.0) : amount; |
116 | 116 | ||
117 | if (is_horizontal(axis)) { | 117 | if (is_horizontal(axis)) { |
118 | if (con->width + amount < MIN_SANE_W) { | 118 | if (con->pending.width + amount < MIN_SANE_W) { |
119 | return; | 119 | return; |
120 | } | 120 | } |
121 | if (next->width - sibling_amount < MIN_SANE_W) { | 121 | if (next->pending.width - sibling_amount < MIN_SANE_W) { |
122 | return; | 122 | return; |
123 | } | 123 | } |
124 | if (prev && prev->width - sibling_amount < MIN_SANE_W) { | 124 | if (prev && prev->pending.width - sibling_amount < MIN_SANE_W) { |
125 | return; | 125 | return; |
126 | } | 126 | } |
127 | if (con->child_total_width <= 0) { | 127 | if (con->child_total_width <= 0) { |
@@ -133,7 +133,7 @@ void container_resize_tiled(struct sway_container *con, | |||
133 | list_t *siblings = container_get_siblings(con); | 133 | list_t *siblings = container_get_siblings(con); |
134 | for (int i = 0; i < siblings->length; ++i) { | 134 | for (int i = 0; i < siblings->length; ++i) { |
135 | struct sway_container *con = siblings->items[i]; | 135 | struct sway_container *con = siblings->items[i]; |
136 | con->width_fraction = con->width / con->child_total_width; | 136 | con->width_fraction = con->pending.width / con->child_total_width; |
137 | } | 137 | } |
138 | 138 | ||
139 | double amount_fraction = (double)amount / con->child_total_width; | 139 | double amount_fraction = (double)amount / con->child_total_width; |
@@ -146,13 +146,13 @@ void container_resize_tiled(struct sway_container *con, | |||
146 | prev->width_fraction -= sibling_amount_fraction; | 146 | prev->width_fraction -= sibling_amount_fraction; |
147 | } | 147 | } |
148 | } else { | 148 | } else { |
149 | if (con->height + amount < MIN_SANE_H) { | 149 | if (con->pending.height + amount < MIN_SANE_H) { |
150 | return; | 150 | return; |
151 | } | 151 | } |
152 | if (next->height - sibling_amount < MIN_SANE_H) { | 152 | if (next->pending.height - sibling_amount < MIN_SANE_H) { |
153 | return; | 153 | return; |
154 | } | 154 | } |
155 | if (prev && prev->height - sibling_amount < MIN_SANE_H) { | 155 | if (prev && prev->pending.height - sibling_amount < MIN_SANE_H) { |
156 | return; | 156 | return; |
157 | } | 157 | } |
158 | if (con->child_total_height <= 0) { | 158 | if (con->child_total_height <= 0) { |
@@ -164,7 +164,7 @@ void container_resize_tiled(struct sway_container *con, | |||
164 | list_t *siblings = container_get_siblings(con); | 164 | list_t *siblings = container_get_siblings(con); |
165 | for (int i = 0; i < siblings->length; ++i) { | 165 | for (int i = 0; i < siblings->length; ++i) { |
166 | struct sway_container *con = siblings->items[i]; | 166 | struct sway_container *con = siblings->items[i]; |
167 | con->height_fraction = con->height / con->child_total_height; | 167 | con->height_fraction = con->pending.height / con->child_total_height; |
168 | } | 168 | } |
169 | 169 | ||
170 | double amount_fraction = (double)amount / con->child_total_height; | 170 | double amount_fraction = (double)amount / con->child_total_height; |
@@ -178,10 +178,10 @@ void container_resize_tiled(struct sway_container *con, | |||
178 | } | 178 | } |
179 | } | 179 | } |
180 | 180 | ||
181 | if (con->parent) { | 181 | if (con->pending.parent) { |
182 | arrange_container(con->parent); | 182 | arrange_container(con->pending.parent); |
183 | } else { | 183 | } else { |
184 | arrange_workspace(con->workspace); | 184 | arrange_workspace(con->pending.workspace); |
185 | } | 185 | } |
186 | } | 186 | } |
187 | 187 | ||
@@ -203,15 +203,15 @@ static struct cmd_results *resize_adjust_floating(uint32_t axis, | |||
203 | int min_width, max_width, min_height, max_height; | 203 | int min_width, max_width, min_height, max_height; |
204 | floating_calculate_constraints(&min_width, &max_width, | 204 | floating_calculate_constraints(&min_width, &max_width, |
205 | &min_height, &max_height); | 205 | &min_height, &max_height); |
206 | if (con->width + grow_width < min_width) { | 206 | if (con->pending.width + grow_width < min_width) { |
207 | grow_width = min_width - con->width; | 207 | grow_width = min_width - con->pending.width; |
208 | } else if (con->width + grow_width > max_width) { | 208 | } else if (con->pending.width + grow_width > max_width) { |
209 | grow_width = max_width - con->width; | 209 | grow_width = max_width - con->pending.width; |
210 | } | 210 | } |
211 | if (con->height + grow_height < min_height) { | 211 | if (con->pending.height + grow_height < min_height) { |
212 | grow_height = min_height - con->height; | 212 | grow_height = min_height - con->pending.height; |
213 | } else if (con->height + grow_height > max_height) { | 213 | } else if (con->pending.height + grow_height > max_height) { |
214 | grow_height = max_height - con->height; | 214 | grow_height = max_height - con->pending.height; |
215 | } | 215 | } |
216 | int grow_x = 0, grow_y = 0; | 216 | int grow_x = 0, grow_y = 0; |
217 | 217 | ||
@@ -227,15 +227,15 @@ static struct cmd_results *resize_adjust_floating(uint32_t axis, | |||
227 | if (grow_width == 0 && grow_height == 0) { | 227 | if (grow_width == 0 && grow_height == 0) { |
228 | return cmd_results_new(CMD_INVALID, "Cannot resize any further"); | 228 | return cmd_results_new(CMD_INVALID, "Cannot resize any further"); |
229 | } | 229 | } |
230 | con->x += grow_x; | 230 | con->pending.x += grow_x; |
231 | con->y += grow_y; | 231 | con->pending.y += grow_y; |
232 | con->width += grow_width; | 232 | con->pending.width += grow_width; |
233 | con->height += grow_height; | 233 | con->pending.height += grow_height; |
234 | 234 | ||
235 | con->content_x += grow_x; | 235 | con->pending.content_x += grow_x; |
236 | con->content_y += grow_y; | 236 | con->pending.content_y += grow_y; |
237 | con->content_width += grow_width; | 237 | con->pending.content_width += grow_width; |
238 | con->content_height += grow_height; | 238 | con->pending.content_height += grow_height; |
239 | 239 | ||
240 | arrange_container(con); | 240 | arrange_container(con); |
241 | 241 | ||
@@ -256,9 +256,9 @@ static struct cmd_results *resize_adjust_tiled(uint32_t axis, | |||
256 | float pct = amount->amount / 100.0f; | 256 | float pct = amount->amount / 100.0f; |
257 | 257 | ||
258 | if (is_horizontal(axis)) { | 258 | if (is_horizontal(axis)) { |
259 | amount->amount = (float)current->width * pct; | 259 | amount->amount = (float)current->pending.width * pct; |
260 | } else { | 260 | } else { |
261 | amount->amount = (float)current->height * pct; | 261 | amount->amount = (float)current->pending.height * pct; |
262 | } | 262 | } |
263 | } | 263 | } |
264 | 264 | ||
@@ -281,20 +281,20 @@ static struct cmd_results *resize_set_tiled(struct sway_container *con, | |||
281 | if (width->unit == MOVEMENT_UNIT_PPT || | 281 | if (width->unit == MOVEMENT_UNIT_PPT || |
282 | width->unit == MOVEMENT_UNIT_DEFAULT) { | 282 | width->unit == MOVEMENT_UNIT_DEFAULT) { |
283 | // Convert to px | 283 | // Convert to px |
284 | struct sway_container *parent = con->parent; | 284 | struct sway_container *parent = con->pending.parent; |
285 | while (parent && parent->layout != L_HORIZ) { | 285 | while (parent && parent->pending.layout != L_HORIZ) { |
286 | parent = parent->parent; | 286 | parent = parent->pending.parent; |
287 | } | 287 | } |
288 | if (parent) { | 288 | if (parent) { |
289 | width->amount = parent->width * width->amount / 100; | 289 | width->amount = parent->pending.width * width->amount / 100; |
290 | } else { | 290 | } else { |
291 | width->amount = con->workspace->width * width->amount / 100; | 291 | width->amount = con->pending.workspace->width * width->amount / 100; |
292 | } | 292 | } |
293 | width->unit = MOVEMENT_UNIT_PX; | 293 | width->unit = MOVEMENT_UNIT_PX; |
294 | } | 294 | } |
295 | if (width->unit == MOVEMENT_UNIT_PX) { | 295 | if (width->unit == MOVEMENT_UNIT_PX) { |
296 | container_resize_tiled(con, AXIS_HORIZONTAL, | 296 | container_resize_tiled(con, AXIS_HORIZONTAL, |
297 | width->amount - con->width); | 297 | width->amount - con->pending.width); |
298 | } | 298 | } |
299 | } | 299 | } |
300 | 300 | ||
@@ -302,20 +302,20 @@ static struct cmd_results *resize_set_tiled(struct sway_container *con, | |||
302 | if (height->unit == MOVEMENT_UNIT_PPT || | 302 | if (height->unit == MOVEMENT_UNIT_PPT || |
303 | height->unit == MOVEMENT_UNIT_DEFAULT) { | 303 | height->unit == MOVEMENT_UNIT_DEFAULT) { |
304 | // Convert to px | 304 | // Convert to px |
305 | struct sway_container *parent = con->parent; | 305 | struct sway_container *parent = con->pending.parent; |
306 | while (parent && parent->layout != L_VERT) { | 306 | while (parent && parent->pending.layout != L_VERT) { |
307 | parent = parent->parent; | 307 | parent = parent->pending.parent; |
308 | } | 308 | } |
309 | if (parent) { | 309 | if (parent) { |
310 | height->amount = parent->height * height->amount / 100; | 310 | height->amount = parent->pending.height * height->amount / 100; |
311 | } else { | 311 | } else { |
312 | height->amount = con->workspace->height * height->amount / 100; | 312 | height->amount = con->pending.workspace->height * height->amount / 100; |
313 | } | 313 | } |
314 | height->unit = MOVEMENT_UNIT_PX; | 314 | height->unit = MOVEMENT_UNIT_PX; |
315 | } | 315 | } |
316 | if (height->unit == MOVEMENT_UNIT_PX) { | 316 | if (height->unit == MOVEMENT_UNIT_PX) { |
317 | container_resize_tiled(con, AXIS_VERTICAL, | 317 | container_resize_tiled(con, AXIS_VERTICAL, |
318 | height->amount - con->height); | 318 | height->amount - con->pending.height); |
319 | } | 319 | } |
320 | } | 320 | } |
321 | 321 | ||
@@ -339,15 +339,15 @@ static struct cmd_results *resize_set_floating(struct sway_container *con, | |||
339 | "Cannot resize a hidden scratchpad container by ppt"); | 339 | "Cannot resize a hidden scratchpad container by ppt"); |
340 | } | 340 | } |
341 | // Convert to px | 341 | // Convert to px |
342 | width->amount = con->workspace->width * width->amount / 100; | 342 | width->amount = con->pending.workspace->width * width->amount / 100; |
343 | width->unit = MOVEMENT_UNIT_PX; | 343 | width->unit = MOVEMENT_UNIT_PX; |
344 | // Falls through | 344 | // Falls through |
345 | case MOVEMENT_UNIT_PX: | 345 | case MOVEMENT_UNIT_PX: |
346 | case MOVEMENT_UNIT_DEFAULT: | 346 | case MOVEMENT_UNIT_DEFAULT: |
347 | width->amount = fmax(min_width, fmin(width->amount, max_width)); | 347 | width->amount = fmax(min_width, fmin(width->amount, max_width)); |
348 | grow_width = width->amount - con->width; | 348 | grow_width = width->amount - con->pending.width; |
349 | con->x -= grow_width / 2; | 349 | con->pending.x -= grow_width / 2; |
350 | con->width = width->amount; | 350 | con->pending.width = width->amount; |
351 | break; | 351 | break; |
352 | case MOVEMENT_UNIT_INVALID: | 352 | case MOVEMENT_UNIT_INVALID: |
353 | sway_assert(false, "invalid width unit"); | 353 | sway_assert(false, "invalid width unit"); |
@@ -363,15 +363,15 @@ static struct cmd_results *resize_set_floating(struct sway_container *con, | |||
363 | "Cannot resize a hidden scratchpad container by ppt"); | 363 | "Cannot resize a hidden scratchpad container by ppt"); |
364 | } | 364 | } |
365 | // Convert to px | 365 | // Convert to px |
366 | height->amount = con->workspace->height * height->amount / 100; | 366 | height->amount = con->pending.workspace->height * height->amount / 100; |
367 | height->unit = MOVEMENT_UNIT_PX; | 367 | height->unit = MOVEMENT_UNIT_PX; |
368 | // Falls through | 368 | // Falls through |
369 | case MOVEMENT_UNIT_PX: | 369 | case MOVEMENT_UNIT_PX: |
370 | case MOVEMENT_UNIT_DEFAULT: | 370 | case MOVEMENT_UNIT_DEFAULT: |
371 | height->amount = fmax(min_height, fmin(height->amount, max_height)); | 371 | height->amount = fmax(min_height, fmin(height->amount, max_height)); |
372 | grow_height = height->amount - con->height; | 372 | grow_height = height->amount - con->pending.height; |
373 | con->y -= grow_height / 2; | 373 | con->pending.y -= grow_height / 2; |
374 | con->height = height->amount; | 374 | con->pending.height = height->amount; |
375 | break; | 375 | break; |
376 | case MOVEMENT_UNIT_INVALID: | 376 | case MOVEMENT_UNIT_INVALID: |
377 | sway_assert(false, "invalid height unit"); | 377 | sway_assert(false, "invalid height unit"); |
@@ -379,10 +379,10 @@ static struct cmd_results *resize_set_floating(struct sway_container *con, | |||
379 | } | 379 | } |
380 | } | 380 | } |
381 | 381 | ||
382 | con->content_x -= grow_width / 2; | 382 | con->pending.content_x -= grow_width / 2; |
383 | con->content_y -= grow_height / 2; | 383 | con->pending.content_y -= grow_height / 2; |
384 | con->content_width += grow_width; | 384 | con->pending.content_width += grow_width; |
385 | con->content_height += grow_height; | 385 | con->pending.content_height += grow_height; |
386 | 386 | ||
387 | arrange_container(con); | 387 | arrange_container(con); |
388 | 388 | ||
@@ -437,10 +437,10 @@ static struct cmd_results *cmd_resize_set(int argc, char **argv) { | |||
437 | // If 0, don't resize that dimension | 437 | // If 0, don't resize that dimension |
438 | struct sway_container *con = config->handler_context.container; | 438 | struct sway_container *con = config->handler_context.container; |
439 | if (width.amount <= 0) { | 439 | if (width.amount <= 0) { |
440 | width.amount = con->width; | 440 | width.amount = con->pending.width; |
441 | } | 441 | } |
442 | if (height.amount <= 0) { | 442 | if (height.amount <= 0) { |
443 | height.amount = con->height; | 443 | height.amount = con->pending.height; |
444 | } | 444 | } |
445 | 445 | ||
446 | if (container_is_floating(con)) { | 446 | if (container_is_floating(con)) { |
diff --git a/sway/commands/scratchpad.c b/sway/commands/scratchpad.c index 34871bc6..c995f2f0 100644 --- a/sway/commands/scratchpad.c +++ b/sway/commands/scratchpad.c | |||
@@ -21,8 +21,8 @@ static void scratchpad_toggle_auto(void) { | |||
21 | // If the focus is in a floating split container, | 21 | // If the focus is in a floating split container, |
22 | // operate on the split container instead of the child. | 22 | // operate on the split container instead of the child. |
23 | if (focus && container_is_floating_or_child(focus)) { | 23 | if (focus && container_is_floating_or_child(focus)) { |
24 | while (focus->parent) { | 24 | while (focus->pending.parent) { |
25 | focus = focus->parent; | 25 | focus = focus->pending.parent; |
26 | } | 26 | } |
27 | } | 27 | } |
28 | 28 | ||
@@ -52,7 +52,7 @@ static void scratchpad_toggle_auto(void) { | |||
52 | // In this case we move it to the current workspace. | 52 | // In this case we move it to the current workspace. |
53 | for (int i = 0; i < root->scratchpad->length; ++i) { | 53 | for (int i = 0; i < root->scratchpad->length; ++i) { |
54 | struct sway_container *con = root->scratchpad->items[i]; | 54 | struct sway_container *con = root->scratchpad->items[i]; |
55 | if (con->parent) { | 55 | if (con->pending.parent) { |
56 | sway_log(SWAY_DEBUG, | 56 | sway_log(SWAY_DEBUG, |
57 | "Moving a visible scratchpad window (%s) to this workspace", | 57 | "Moving a visible scratchpad window (%s) to this workspace", |
58 | con->title); | 58 | con->title); |
@@ -80,7 +80,7 @@ static void scratchpad_toggle_container(struct sway_container *con) { | |||
80 | struct sway_seat *seat = input_manager_current_seat(); | 80 | struct sway_seat *seat = input_manager_current_seat(); |
81 | struct sway_workspace *ws = seat_get_focused_workspace(seat); | 81 | struct sway_workspace *ws = seat_get_focused_workspace(seat); |
82 | // Check if it matches a currently visible scratchpad window and hide it. | 82 | // Check if it matches a currently visible scratchpad window and hide it. |
83 | if (con->workspace && ws == con->workspace) { | 83 | if (con->pending.workspace && ws == con->pending.workspace) { |
84 | root_scratchpad_hide(con); | 84 | root_scratchpad_hide(con); |
85 | return; | 85 | return; |
86 | } | 86 | } |
@@ -105,21 +105,22 @@ struct cmd_results *cmd_scratchpad(int argc, char **argv) { | |||
105 | return cmd_results_new(CMD_INVALID, "Scratchpad is empty"); | 105 | return cmd_results_new(CMD_INVALID, "Scratchpad is empty"); |
106 | } | 106 | } |
107 | 107 | ||
108 | if (config->handler_context.using_criteria) { | 108 | if (config->handler_context.node_overridden) { |
109 | struct sway_container *con = config->handler_context.container; | 109 | struct sway_container *con = config->handler_context.container; |
110 | 110 | ||
111 | // If the container is in a floating split container, | 111 | // If the container is in a floating split container, |
112 | // operate on the split container instead of the child. | 112 | // operate on the split container instead of the child. |
113 | if (container_is_floating_or_child(con)) { | 113 | if (con && container_is_floating_or_child(con)) { |
114 | while (con->parent) { | 114 | while (con->pending.parent) { |
115 | con = con->parent; | 115 | con = con->pending.parent; |
116 | } | 116 | } |
117 | } | 117 | } |
118 | 118 | ||
119 | // If using criteria, this command is executed for every container which | 119 | // If using criteria, this command is executed for every container which |
120 | // matches the criteria. If this container isn't in the scratchpad, | 120 | // matches the criteria. If this container isn't in the scratchpad, |
121 | // we'll just silently return a success. | 121 | // we'll just silently return a success. The same is true if the |
122 | if (!con->scratchpad) { | 122 | // overridden node is not a container. |
123 | if (!con || !con->scratchpad) { | ||
123 | return cmd_results_new(CMD_SUCCESS, NULL); | 124 | return cmd_results_new(CMD_SUCCESS, NULL); |
124 | } | 125 | } |
125 | scratchpad_toggle_container(con); | 126 | scratchpad_toggle_container(con); |
diff --git a/sway/commands/seat.c b/sway/commands/seat.c index 84c6ba53..2d197b69 100644 --- a/sway/commands/seat.c +++ b/sway/commands/seat.c | |||
@@ -8,13 +8,13 @@ | |||
8 | 8 | ||
9 | // must be in order for the bsearch | 9 | // must be in order for the bsearch |
10 | // these handlers perform actions on the seat | 10 | // these handlers perform actions on the seat |
11 | static struct cmd_handler seat_action_handlers[] = { | 11 | static const struct cmd_handler seat_action_handlers[] = { |
12 | { "cursor", seat_cmd_cursor }, | 12 | { "cursor", seat_cmd_cursor }, |
13 | }; | 13 | }; |
14 | 14 | ||
15 | // must be in order for the bsearch | 15 | // must be in order for the bsearch |
16 | // these handlers alter the seat config | 16 | // these handlers alter the seat config |
17 | static struct cmd_handler seat_handlers[] = { | 17 | static const struct cmd_handler seat_handlers[] = { |
18 | { "attach", seat_cmd_attach }, | 18 | { "attach", seat_cmd_attach }, |
19 | { "fallback", seat_cmd_fallback }, | 19 | { "fallback", seat_cmd_fallback }, |
20 | { "hide_cursor", seat_cmd_hide_cursor }, | 20 | { "hide_cursor", seat_cmd_hide_cursor }, |
diff --git a/sway/commands/seat/attach.c b/sway/commands/seat/attach.c index 7615eef9..00bfdab6 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) { | |||
12 | if (!config->handler_context.seat_config) { | 12 | if (!config->handler_context.seat_config) { |
13 | return cmd_results_new(CMD_FAILURE, "No seat defined"); | 13 | return cmd_results_new(CMD_FAILURE, "No seat defined"); |
14 | } | 14 | } |
15 | if (config->reading) { | 15 | if (!config->active) { |
16 | return cmd_results_new(CMD_DEFER, NULL); | 16 | return cmd_results_new(CMD_DEFER, NULL); |
17 | } | 17 | } |
18 | 18 | ||
diff --git a/sway/commands/split.c b/sway/commands/split.c index 782bab02..c8a2cfc1 100644 --- a/sway/commands/split.c +++ b/sway/commands/split.c | |||
@@ -14,7 +14,7 @@ static struct cmd_results *do_split(int layout) { | |||
14 | struct sway_workspace *ws = config->handler_context.workspace; | 14 | struct sway_workspace *ws = config->handler_context.workspace; |
15 | if (con) { | 15 | if (con) { |
16 | if (container_is_scratchpad_hidden_or_child(con) && | 16 | if (container_is_scratchpad_hidden_or_child(con) && |
17 | con->fullscreen_mode != FULLSCREEN_GLOBAL) { | 17 | con->pending.fullscreen_mode != FULLSCREEN_GLOBAL) { |
18 | return cmd_results_new(CMD_FAILURE, | 18 | return cmd_results_new(CMD_FAILURE, |
19 | "Cannot split a hidden scratchpad container"); | 19 | "Cannot split a hidden scratchpad container"); |
20 | } | 20 | } |
@@ -32,6 +32,24 @@ static struct cmd_results *do_split(int layout) { | |||
32 | return cmd_results_new(CMD_SUCCESS, NULL); | 32 | return cmd_results_new(CMD_SUCCESS, NULL); |
33 | } | 33 | } |
34 | 34 | ||
35 | static struct cmd_results *do_unsplit() { | ||
36 | struct sway_container *con = config->handler_context.container; | ||
37 | struct sway_workspace *ws = config->handler_context.workspace; | ||
38 | |||
39 | if (con && con->pending.parent && con->pending.parent->pending.children->length == 1) { | ||
40 | container_flatten(con->pending.parent); | ||
41 | } else { | ||
42 | return cmd_results_new(CMD_FAILURE, "Can only flatten a child container with no siblings"); | ||
43 | } | ||
44 | |||
45 | if (root->fullscreen_global) { | ||
46 | arrange_root(); | ||
47 | } else { | ||
48 | arrange_workspace(ws); | ||
49 | } | ||
50 | return cmd_results_new(CMD_SUCCESS, NULL); | ||
51 | } | ||
52 | |||
35 | struct cmd_results *cmd_split(int argc, char **argv) { | 53 | struct cmd_results *cmd_split(int argc, char **argv) { |
36 | struct cmd_results *error = NULL; | 54 | struct cmd_results *error = NULL; |
37 | if ((error = checkarg(argc, "split", EXPECTED_EQUAL_TO, 1))) { | 55 | if ((error = checkarg(argc, "split", EXPECTED_EQUAL_TO, 1))) { |
@@ -55,6 +73,9 @@ struct cmd_results *cmd_split(int argc, char **argv) { | |||
55 | } else { | 73 | } else { |
56 | return do_split(L_VERT); | 74 | return do_split(L_VERT); |
57 | } | 75 | } |
76 | } else if (strcasecmp(argv[0], "n") == 0 || | ||
77 | strcasecmp(argv[0], "none") == 0) { | ||
78 | return do_unsplit(); | ||
58 | } else { | 79 | } else { |
59 | return cmd_results_new(CMD_FAILURE, | 80 | return cmd_results_new(CMD_FAILURE, |
60 | "Invalid split command (expected either horizontal or vertical)."); | 81 | "Invalid split command (expected either horizontal or vertical)."); |
diff --git a/sway/commands/sticky.c b/sway/commands/sticky.c index 3c93a276..9b09a0f9 100644 --- a/sway/commands/sticky.c +++ b/sway/commands/sticky.c | |||
@@ -29,14 +29,14 @@ struct cmd_results *cmd_sticky(int argc, char **argv) { | |||
29 | !container_is_scratchpad_hidden(container)) { | 29 | !container_is_scratchpad_hidden(container)) { |
30 | // move container to active workspace | 30 | // move container to active workspace |
31 | struct sway_workspace *active_workspace = | 31 | struct sway_workspace *active_workspace = |
32 | output_get_active_workspace(container->workspace->output); | 32 | output_get_active_workspace(container->pending.workspace->output); |
33 | if (!sway_assert(active_workspace, | 33 | if (!sway_assert(active_workspace, |
34 | "Expected output to have a workspace")) { | 34 | "Expected output to have a workspace")) { |
35 | return cmd_results_new(CMD_FAILURE, | 35 | return cmd_results_new(CMD_FAILURE, |
36 | "Expected output to have a workspace"); | 36 | "Expected output to have a workspace"); |
37 | } | 37 | } |
38 | if (container->workspace != active_workspace) { | 38 | if (container->pending.workspace != active_workspace) { |
39 | struct sway_workspace *old_workspace = container->workspace; | 39 | struct sway_workspace *old_workspace = container->pending.workspace; |
40 | container_detach(container); | 40 | container_detach(container); |
41 | workspace_add_floating(active_workspace, container); | 41 | workspace_add_floating(active_workspace, container); |
42 | container_handle_fullscreen_reparent(container); | 42 | container_handle_fullscreen_reparent(container); |
diff --git a/sway/commands/swap.c b/sway/commands/swap.c index a7f9691b..ce5e5128 100644 --- a/sway/commands/swap.c +++ b/sway/commands/swap.c | |||
@@ -16,46 +16,46 @@ static const char expected_syntax[] = | |||
16 | static void swap_places(struct sway_container *con1, | 16 | static void swap_places(struct sway_container *con1, |
17 | struct sway_container *con2) { | 17 | struct sway_container *con2) { |
18 | struct sway_container *temp = malloc(sizeof(struct sway_container)); | 18 | struct sway_container *temp = malloc(sizeof(struct sway_container)); |
19 | temp->x = con1->x; | 19 | temp->pending.x = con1->pending.x; |
20 | temp->y = con1->y; | 20 | temp->pending.y = con1->pending.y; |
21 | temp->width = con1->width; | 21 | temp->pending.width = con1->pending.width; |
22 | temp->height = con1->height; | 22 | temp->pending.height = con1->pending.height; |
23 | temp->width_fraction = con1->width_fraction; | 23 | temp->width_fraction = con1->width_fraction; |
24 | temp->height_fraction = con1->height_fraction; | 24 | temp->height_fraction = con1->height_fraction; |
25 | temp->parent = con1->parent; | 25 | temp->pending.parent = con1->pending.parent; |
26 | temp->workspace = con1->workspace; | 26 | temp->pending.workspace = con1->pending.workspace; |
27 | bool temp_floating = container_is_floating(con1); | 27 | bool temp_floating = container_is_floating(con1); |
28 | 28 | ||
29 | con1->x = con2->x; | 29 | con1->pending.x = con2->pending.x; |
30 | con1->y = con2->y; | 30 | con1->pending.y = con2->pending.y; |
31 | con1->width = con2->width; | 31 | con1->pending.width = con2->pending.width; |
32 | con1->height = con2->height; | 32 | con1->pending.height = con2->pending.height; |
33 | con1->width_fraction = con2->width_fraction; | 33 | con1->width_fraction = con2->width_fraction; |
34 | con1->height_fraction = con2->height_fraction; | 34 | con1->height_fraction = con2->height_fraction; |
35 | 35 | ||
36 | con2->x = temp->x; | 36 | con2->pending.x = temp->pending.x; |
37 | con2->y = temp->y; | 37 | con2->pending.y = temp->pending.y; |
38 | con2->width = temp->width; | 38 | con2->pending.width = temp->pending.width; |
39 | con2->height = temp->height; | 39 | con2->pending.height = temp->pending.height; |
40 | con2->width_fraction = temp->width_fraction; | 40 | con2->width_fraction = temp->width_fraction; |
41 | con2->height_fraction = temp->height_fraction; | 41 | con2->height_fraction = temp->height_fraction; |
42 | 42 | ||
43 | int temp_index = container_sibling_index(con1); | 43 | int temp_index = container_sibling_index(con1); |
44 | if (con2->parent) { | 44 | if (con2->pending.parent) { |
45 | container_insert_child(con2->parent, con1, | 45 | container_insert_child(con2->pending.parent, con1, |
46 | container_sibling_index(con2)); | 46 | container_sibling_index(con2)); |
47 | } else if (container_is_floating(con2)) { | 47 | } else if (container_is_floating(con2)) { |
48 | workspace_add_floating(con2->workspace, con1); | 48 | workspace_add_floating(con2->pending.workspace, con1); |
49 | } else { | 49 | } else { |
50 | workspace_insert_tiling(con2->workspace, con1, | 50 | workspace_insert_tiling(con2->pending.workspace, con1, |
51 | container_sibling_index(con2)); | 51 | container_sibling_index(con2)); |
52 | } | 52 | } |
53 | if (temp->parent) { | 53 | if (temp->pending.parent) { |
54 | container_insert_child(temp->parent, con2, temp_index); | 54 | container_insert_child(temp->pending.parent, con2, temp_index); |
55 | } else if (temp_floating) { | 55 | } else if (temp_floating) { |
56 | workspace_add_floating(temp->workspace, con2); | 56 | workspace_add_floating(temp->pending.workspace, con2); |
57 | } else { | 57 | } else { |
58 | workspace_insert_tiling(temp->workspace, con2, temp_index); | 58 | workspace_insert_tiling(temp->pending.workspace, con2, temp_index); |
59 | } | 59 | } |
60 | 60 | ||
61 | free(temp); | 61 | free(temp); |
@@ -65,8 +65,8 @@ static void swap_focus(struct sway_container *con1, | |||
65 | struct sway_container *con2, struct sway_seat *seat, | 65 | struct sway_container *con2, struct sway_seat *seat, |
66 | struct sway_container *focus) { | 66 | struct sway_container *focus) { |
67 | if (focus == con1 || focus == con2) { | 67 | if (focus == con1 || focus == con2) { |
68 | struct sway_workspace *ws1 = con1->workspace; | 68 | struct sway_workspace *ws1 = con1->pending.workspace; |
69 | struct sway_workspace *ws2 = con2->workspace; | 69 | struct sway_workspace *ws2 = con2->pending.workspace; |
70 | enum sway_container_layout layout1 = container_parent_layout(con1); | 70 | enum sway_container_layout layout1 = container_parent_layout(con1); |
71 | enum sway_container_layout layout2 = container_parent_layout(con2); | 71 | enum sway_container_layout layout2 = container_parent_layout(con2); |
72 | if (focus == con1 && (layout2 == L_TABBED || layout2 == L_STACKED)) { | 72 | if (focus == con1 && (layout2 == L_TABBED || layout2 == L_STACKED)) { |
@@ -125,8 +125,8 @@ void container_swap(struct sway_container *con1, struct sway_container *con2) { | |||
125 | root_scratchpad_remove_container(con2); | 125 | root_scratchpad_remove_container(con2); |
126 | } | 126 | } |
127 | 127 | ||
128 | enum sway_fullscreen_mode fs1 = con1->fullscreen_mode; | 128 | enum sway_fullscreen_mode fs1 = con1->pending.fullscreen_mode; |
129 | enum sway_fullscreen_mode fs2 = con2->fullscreen_mode; | 129 | enum sway_fullscreen_mode fs2 = con2->pending.fullscreen_mode; |
130 | if (fs1) { | 130 | if (fs1) { |
131 | container_fullscreen_disable(con1); | 131 | container_fullscreen_disable(con1); |
132 | } | 132 | } |
@@ -137,9 +137,9 @@ void container_swap(struct sway_container *con1, struct sway_container *con2) { | |||
137 | struct sway_seat *seat = config->handler_context.seat; | 137 | struct sway_seat *seat = config->handler_context.seat; |
138 | struct sway_container *focus = seat_get_focused_container(seat); | 138 | struct sway_container *focus = seat_get_focused_container(seat); |
139 | struct sway_workspace *vis1 = | 139 | struct sway_workspace *vis1 = |
140 | output_get_active_workspace(con1->workspace->output); | 140 | output_get_active_workspace(con1->pending.workspace->output); |
141 | struct sway_workspace *vis2 = | 141 | struct sway_workspace *vis2 = |
142 | output_get_active_workspace(con2->workspace->output); | 142 | output_get_active_workspace(con2->pending.workspace->output); |
143 | if (!sway_assert(vis1 && vis2, "con1 or con2 are on an output without a" | 143 | if (!sway_assert(vis1 && vis2, "con1 or con2 are on an output without a" |
144 | "workspace. This should not happen")) { | 144 | "workspace. This should not happen")) { |
145 | return; | 145 | return; |
diff --git a/sway/commands/title_format.c b/sway/commands/title_format.c index 9d312470..a2446b7e 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) { | |||
23 | } | 23 | } |
24 | view->title_format = format; | 24 | view->title_format = format; |
25 | view_update_title(view, true); | 25 | view_update_title(view, true); |
26 | config_update_font_height(true); | ||
27 | return cmd_results_new(CMD_SUCCESS, NULL); | 26 | return cmd_results_new(CMD_SUCCESS, NULL); |
28 | } | 27 | } |
diff --git a/sway/commands/unmark.c b/sway/commands/unmark.c index cedfcfb2..19274dfb 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) { | |||
21 | struct cmd_results *cmd_unmark(int argc, char **argv) { | 21 | struct cmd_results *cmd_unmark(int argc, char **argv) { |
22 | // Determine the container | 22 | // Determine the container |
23 | struct sway_container *con = NULL; | 23 | struct sway_container *con = NULL; |
24 | if (config->handler_context.using_criteria) { | 24 | if (config->handler_context.node_overridden) { |
25 | con = config->handler_context.container; | 25 | con = config->handler_context.container; |
26 | } | 26 | } |
27 | 27 | ||
diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index 9ff1c97d..79f3667a 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c | |||
@@ -182,21 +182,16 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { | |||
182 | "Can't switch workspaces while fullscreen global"); | 182 | "Can't switch workspaces while fullscreen global"); |
183 | } | 183 | } |
184 | 184 | ||
185 | bool no_auto_back_and_forth = false; | 185 | bool auto_back_and_forth = true; |
186 | while (strcasecmp(argv[0], "--no-auto-back-and-forth") == 0) { | 186 | while (strcasecmp(argv[0], "--no-auto-back-and-forth") == 0) { |
187 | no_auto_back_and_forth = true; | 187 | auto_back_and_forth = false; |
188 | if ((error = checkarg(--argc, "workspace", EXPECTED_AT_LEAST, 1))) { | 188 | if ((error = checkarg(--argc, "workspace", EXPECTED_AT_LEAST, 1))) { |
189 | return error; | 189 | return error; |
190 | } | 190 | } |
191 | ++argv; | 191 | ++argv; |
192 | } | 192 | } |
193 | 193 | ||
194 | bool create = argc > 1 && strcasecmp(argv[1], "--create") == 0; | ||
195 | struct sway_seat *seat = config->handler_context.seat; | 194 | struct sway_seat *seat = config->handler_context.seat; |
196 | struct sway_workspace *current = seat_get_focused_workspace(seat); | ||
197 | if (!current) { | ||
198 | return cmd_results_new(CMD_FAILURE, "No workspace to switch from"); | ||
199 | } | ||
200 | 195 | ||
201 | struct sway_workspace *ws = NULL; | 196 | struct sway_workspace *ws = NULL; |
202 | if (strcasecmp(argv[0], "number") == 0) { | 197 | if (strcasecmp(argv[0], "number") == 0) { |
@@ -213,14 +208,15 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { | |||
213 | ws = workspace_create(NULL, name); | 208 | ws = workspace_create(NULL, name); |
214 | free(name); | 209 | free(name); |
215 | } | 210 | } |
211 | if (ws && auto_back_and_forth) { | ||
212 | ws = workspace_auto_back_and_forth(ws); | ||
213 | } | ||
216 | } else if (strcasecmp(argv[0], "next") == 0 || | 214 | } else if (strcasecmp(argv[0], "next") == 0 || |
217 | strcasecmp(argv[0], "prev") == 0 || | 215 | strcasecmp(argv[0], "prev") == 0 || |
216 | strcasecmp(argv[0], "next_on_output") == 0 || | ||
217 | strcasecmp(argv[0], "prev_on_output") == 0 || | ||
218 | strcasecmp(argv[0], "current") == 0) { | 218 | strcasecmp(argv[0], "current") == 0) { |
219 | ws = workspace_by_name(argv[0]); | 219 | ws = workspace_by_name(argv[0]); |
220 | } else if (strcasecmp(argv[0], "next_on_output") == 0) { | ||
221 | ws = workspace_output_next(current, create); | ||
222 | } else if (strcasecmp(argv[0], "prev_on_output") == 0) { | ||
223 | ws = workspace_output_prev(current, create); | ||
224 | } else if (strcasecmp(argv[0], "back_and_forth") == 0) { | 220 | } else if (strcasecmp(argv[0], "back_and_forth") == 0) { |
225 | if (!seat->prev_workspace_name) { | 221 | if (!seat->prev_workspace_name) { |
226 | return cmd_results_new(CMD_INVALID, | 222 | return cmd_results_new(CMD_INVALID, |
@@ -235,11 +231,14 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { | |||
235 | ws = workspace_create(NULL, name); | 231 | ws = workspace_create(NULL, name); |
236 | } | 232 | } |
237 | free(name); | 233 | free(name); |
234 | if (ws && auto_back_and_forth) { | ||
235 | ws = workspace_auto_back_and_forth(ws); | ||
236 | } | ||
238 | } | 237 | } |
239 | if (!ws) { | 238 | if (!ws) { |
240 | return cmd_results_new(CMD_FAILURE, "No workspace to switch to"); | 239 | return cmd_results_new(CMD_FAILURE, "No workspace to switch to"); |
241 | } | 240 | } |
242 | workspace_switch(ws, no_auto_back_and_forth); | 241 | workspace_switch(ws); |
243 | seat_consider_warp_to_focus(seat); | 242 | seat_consider_warp_to_focus(seat); |
244 | } | 243 | } |
245 | return cmd_results_new(CMD_SUCCESS, NULL); | 244 | return cmd_results_new(CMD_SUCCESS, NULL); |
diff --git a/sway/config.c b/sway/config.c index 6e665434..e3daacda 100644 --- a/sway/config.c +++ b/sway/config.c | |||
@@ -26,7 +26,7 @@ | |||
26 | #include "sway/tree/arrange.h" | 26 | #include "sway/tree/arrange.h" |
27 | #include "sway/tree/root.h" | 27 | #include "sway/tree/root.h" |
28 | #include "sway/tree/workspace.h" | 28 | #include "sway/tree/workspace.h" |
29 | #include "cairo.h" | 29 | #include "cairo_util.h" |
30 | #include "pango.h" | 30 | #include "pango.h" |
31 | #include "stringop.h" | 31 | #include "stringop.h" |
32 | #include "list.h" | 32 | #include "list.h" |
@@ -236,7 +236,6 @@ static void config_defaults(struct sway_config *config) { | |||
236 | config->default_layout = L_NONE; | 236 | config->default_layout = L_NONE; |
237 | config->default_orientation = L_NONE; | 237 | config->default_orientation = L_NONE; |
238 | if (!(config->font = strdup("monospace 10"))) goto cleanup; | 238 | if (!(config->font = strdup("monospace 10"))) goto cleanup; |
239 | config->font_height = 17; // height of monospace 10 | ||
240 | config->urgent_timeout = 500; | 239 | config->urgent_timeout = 500; |
241 | config->focus_on_window_activation = FOWA_URGENT; | 240 | config->focus_on_window_activation = FOWA_URGENT; |
242 | config->popup_during_fullscreen = POPUP_SMART; | 241 | config->popup_during_fullscreen = POPUP_SMART; |
@@ -338,35 +337,62 @@ static bool file_exists(const char *path) { | |||
338 | return path && access(path, R_OK) != -1; | 337 | return path && access(path, R_OK) != -1; |
339 | } | 338 | } |
340 | 339 | ||
340 | static char *config_path(const char *prefix, const char *config_folder) { | ||
341 | if (!prefix || !prefix[0] || !config_folder || !config_folder[0]) { | ||
342 | return NULL; | ||
343 | } | ||
344 | |||
345 | const char *filename = "config"; | ||
346 | |||
347 | size_t size = 3 + strlen(prefix) + strlen(config_folder) + strlen(filename); | ||
348 | char *path = calloc(size, sizeof(char)); | ||
349 | snprintf(path, size, "%s/%s/%s", prefix, config_folder, filename); | ||
350 | return path; | ||
351 | } | ||
352 | |||
341 | static char *get_config_path(void) { | 353 | static char *get_config_path(void) { |
342 | static const char *config_paths[] = { | 354 | char *path = NULL; |
343 | "$HOME/.sway/config", | 355 | const char *home = getenv("HOME"); |
344 | "$XDG_CONFIG_HOME/sway/config", | 356 | char *config_home_fallback = NULL; |
345 | "$HOME/.i3/config", | 357 | |
346 | "$XDG_CONFIG_HOME/i3/config", | 358 | const char *config_home = getenv("XDG_CONFIG_HOME"); |
347 | SYSCONFDIR "/sway/config", | 359 | if ((config_home == NULL || config_home[0] == '\0') && home != NULL) { |
348 | SYSCONFDIR "/i3/config", | 360 | size_t size_fallback = 1 + strlen(home) + strlen("/.config"); |
361 | config_home_fallback = calloc(size_fallback, sizeof(char)); | ||
362 | if (config_home_fallback != NULL) | ||
363 | snprintf(config_home_fallback, size_fallback, "%s/.config", home); | ||
364 | config_home = config_home_fallback; | ||
365 | } | ||
366 | |||
367 | struct config_path { | ||
368 | const char *prefix; | ||
369 | const char *config_folder; | ||
349 | }; | 370 | }; |
350 | 371 | ||
351 | char *config_home = getenv("XDG_CONFIG_HOME"); | 372 | struct config_path config_paths[] = { |
352 | if (!config_home || !*config_home) { | 373 | { .prefix = home, .config_folder = ".sway"}, |
353 | config_paths[1] = "$HOME/.config/sway/config"; | 374 | { .prefix = config_home, .config_folder = "sway"}, |
354 | config_paths[3] = "$HOME/.config/i3/config"; | 375 | { .prefix = home, .config_folder = ".i3"}, |
355 | } | 376 | { .prefix = config_home, .config_folder = "i3"}, |
377 | { .prefix = SYSCONFDIR, .config_folder = "sway"}, | ||
378 | { .prefix = SYSCONFDIR, .config_folder = "i3"} | ||
379 | }; | ||
356 | 380 | ||
357 | for (size_t i = 0; i < sizeof(config_paths) / sizeof(char *); ++i) { | 381 | size_t num_config_paths = sizeof(config_paths)/sizeof(config_paths[0]); |
358 | wordexp_t p; | 382 | for (size_t i = 0; i < num_config_paths; i++) { |
359 | if (wordexp(config_paths[i], &p, WRDE_UNDEF) == 0) { | 383 | path = config_path(config_paths[i].prefix, config_paths[i].config_folder); |
360 | char *path = strdup(p.we_wordv[0]); | 384 | if (!path) { |
361 | wordfree(&p); | 385 | continue; |
362 | if (file_exists(path)) { | 386 | } |
363 | return path; | 387 | if (file_exists(path)) { |
364 | } | 388 | break; |
365 | free(path); | ||
366 | } | 389 | } |
390 | free(path); | ||
391 | path = NULL; | ||
367 | } | 392 | } |
368 | 393 | ||
369 | return NULL; | 394 | free(config_home_fallback); |
395 | return path; | ||
370 | } | 396 | } |
371 | 397 | ||
372 | static bool load_config(const char *path, struct sway_config *config, | 398 | static bool load_config(const char *path, struct sway_config *config, |
@@ -514,6 +540,9 @@ bool load_main_config(const char *file, bool is_active, bool validating) { | |||
514 | return success; | 540 | return success; |
515 | } | 541 | } |
516 | 542 | ||
543 | // Only really necessary if not explicitly `font` is set in the config. | ||
544 | config_update_font_height(); | ||
545 | |||
517 | if (is_active && !validating) { | 546 | if (is_active && !validating) { |
518 | input_manager_verify_fallback_seat(); | 547 | input_manager_verify_fallback_seat(); |
519 | 548 | ||
@@ -964,31 +993,11 @@ int workspace_output_cmp_workspace(const void *a, const void *b) { | |||
964 | return lenient_strcmp(wsa->workspace, wsb->workspace); | 993 | return lenient_strcmp(wsa->workspace, wsb->workspace); |
965 | } | 994 | } |
966 | 995 | ||
967 | static void find_font_height_iterator(struct sway_container *con, void *data) { | ||
968 | size_t amount_below_baseline = con->title_height - con->title_baseline; | ||
969 | size_t extended_height = config->font_baseline + amount_below_baseline; | ||
970 | if (extended_height > config->font_height) { | ||
971 | config->font_height = extended_height; | ||
972 | } | ||
973 | } | ||
974 | |||
975 | static void find_baseline_iterator(struct sway_container *con, void *data) { | ||
976 | bool *recalculate = data; | ||
977 | if (*recalculate) { | ||
978 | container_calculate_title_height(con); | ||
979 | } | ||
980 | if (con->title_baseline > config->font_baseline) { | ||
981 | config->font_baseline = con->title_baseline; | ||
982 | } | ||
983 | } | ||
984 | 996 | ||
985 | void config_update_font_height(bool recalculate) { | 997 | void config_update_font_height(void) { |
986 | size_t prev_max_height = config->font_height; | 998 | int prev_max_height = config->font_height; |
987 | config->font_height = 0; | ||
988 | config->font_baseline = 0; | ||
989 | 999 | ||
990 | root_for_each_container(find_baseline_iterator, &recalculate); | 1000 | get_text_metrics(config->font, &config->font_height, &config->font_baseline); |
991 | root_for_each_container(find_font_height_iterator, NULL); | ||
992 | 1001 | ||
993 | if (config->font_height != prev_max_height) { | 1002 | if (config->font_height != prev_max_height) { |
994 | arrange_root(); | 1003 | arrange_root(); |
diff --git a/sway/config/bar.c b/sway/config/bar.c index 767534a6..e09add44 100644 --- a/sway/config/bar.c +++ b/sway/config/bar.c | |||
@@ -91,7 +91,7 @@ struct bar_config *default_bar_config(void) { | |||
91 | } | 91 | } |
92 | bar->outputs = NULL; | 92 | bar->outputs = NULL; |
93 | bar->position = strdup("bottom"); | 93 | bar->position = strdup("bottom"); |
94 | bar->pango_markup = false; | 94 | bar->pango_markup = PANGO_MARKUP_DEFAULT; |
95 | bar->swaybar_command = NULL; | 95 | bar->swaybar_command = NULL; |
96 | bar->font = NULL; | 96 | bar->font = NULL; |
97 | bar->height = 0; | 97 | bar->height = 0; |
@@ -217,6 +217,7 @@ static void invoke_swaybar(struct bar_config *bar) { | |||
217 | sigset_t set; | 217 | sigset_t set; |
218 | sigemptyset(&set); | 218 | sigemptyset(&set); |
219 | sigprocmask(SIG_SETMASK, &set, NULL); | 219 | sigprocmask(SIG_SETMASK, &set, NULL); |
220 | signal(SIGPIPE, SIG_DFL); | ||
220 | 221 | ||
221 | pid = fork(); | 222 | pid = fork(); |
222 | if (pid < 0) { | 223 | if (pid < 0) { |
diff --git a/sway/config/output.c b/sway/config/output.c index c9ec6745..8e937b28 100644 --- a/sway/config/output.c +++ b/sway/config/output.c | |||
@@ -8,6 +8,7 @@ | |||
8 | #include <wlr/types/wlr_cursor.h> | 8 | #include <wlr/types/wlr_cursor.h> |
9 | #include <wlr/types/wlr_output_layout.h> | 9 | #include <wlr/types/wlr_output_layout.h> |
10 | #include <wlr/types/wlr_output.h> | 10 | #include <wlr/types/wlr_output.h> |
11 | #include <wlr/backend/drm.h> | ||
11 | #include "sway/config.h" | 12 | #include "sway/config.h" |
12 | #include "sway/input/cursor.h" | 13 | #include "sway/input/cursor.h" |
13 | #include "sway/output.h" | 14 | #include "sway/output.h" |
@@ -58,6 +59,7 @@ struct output_config *new_output_config(const char *name) { | |||
58 | oc->width = oc->height = -1; | 59 | oc->width = oc->height = -1; |
59 | oc->refresh_rate = -1; | 60 | oc->refresh_rate = -1; |
60 | oc->custom_mode = -1; | 61 | oc->custom_mode = -1; |
62 | oc->drm_mode.type = -1; | ||
61 | oc->x = oc->y = -1; | 63 | oc->x = oc->y = -1; |
62 | oc->scale = -1; | 64 | oc->scale = -1; |
63 | oc->scale_filter = SCALE_FILTER_DEFAULT; | 65 | oc->scale_filter = SCALE_FILTER_DEFAULT; |
@@ -99,6 +101,9 @@ void merge_output_config(struct output_config *dst, struct output_config *src) { | |||
99 | if (src->custom_mode != -1) { | 101 | if (src->custom_mode != -1) { |
100 | dst->custom_mode = src->custom_mode; | 102 | dst->custom_mode = src->custom_mode; |
101 | } | 103 | } |
104 | if (src->drm_mode.type != (uint32_t) -1) { | ||
105 | memcpy(&dst->drm_mode, &src->drm_mode, sizeof(src->drm_mode)); | ||
106 | } | ||
102 | if (src->transform != -1) { | 107 | if (src->transform != -1) { |
103 | dst->transform = src->transform; | 108 | dst->transform = src->transform; |
104 | } | 109 | } |
@@ -271,6 +276,18 @@ static void set_mode(struct wlr_output *output, int width, int height, | |||
271 | wlr_output_set_mode(output, best); | 276 | wlr_output_set_mode(output, best); |
272 | } | 277 | } |
273 | 278 | ||
279 | static void set_modeline(struct wlr_output *output, drmModeModeInfo *drm_mode) { | ||
280 | if (!wlr_output_is_drm(output)) { | ||
281 | sway_log(SWAY_ERROR, "Modeline can only be set to DRM output"); | ||
282 | return; | ||
283 | } | ||
284 | sway_log(SWAY_DEBUG, "Assigning custom modeline to %s", output->name); | ||
285 | struct wlr_output_mode *mode = wlr_drm_connector_add_mode(output, drm_mode); | ||
286 | if (mode) { | ||
287 | wlr_output_set_mode(output, mode); | ||
288 | } | ||
289 | } | ||
290 | |||
274 | /* Some manufacturers hardcode the aspect-ratio of the output in the physical | 291 | /* Some manufacturers hardcode the aspect-ratio of the output in the physical |
275 | * size field. */ | 292 | * size field. */ |
276 | static bool phys_size_is_aspect_ratio(struct wlr_output *output) { | 293 | static bool phys_size_is_aspect_ratio(struct wlr_output *output) { |
@@ -351,14 +368,36 @@ static void queue_output_config(struct output_config *oc, | |||
351 | sway_log(SWAY_DEBUG, "Turning on output %s", wlr_output->name); | 368 | sway_log(SWAY_DEBUG, "Turning on output %s", wlr_output->name); |
352 | wlr_output_enable(wlr_output, true); | 369 | wlr_output_enable(wlr_output, true); |
353 | 370 | ||
354 | if (oc && oc->width > 0 && oc->height > 0) { | 371 | if (oc && oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t) -1) { |
372 | sway_log(SWAY_DEBUG, "Set %s modeline", | ||
373 | wlr_output->name); | ||
374 | set_modeline(wlr_output, &oc->drm_mode); | ||
375 | } else if (oc && oc->width > 0 && oc->height > 0) { | ||
355 | sway_log(SWAY_DEBUG, "Set %s mode to %dx%d (%f Hz)", | 376 | sway_log(SWAY_DEBUG, "Set %s mode to %dx%d (%f Hz)", |
356 | wlr_output->name, oc->width, oc->height, oc->refresh_rate); | 377 | wlr_output->name, oc->width, oc->height, oc->refresh_rate); |
357 | set_mode(wlr_output, oc->width, oc->height, | 378 | set_mode(wlr_output, oc->width, oc->height, |
358 | oc->refresh_rate, oc->custom_mode == 1); | 379 | oc->refresh_rate, oc->custom_mode == 1); |
359 | } else if (!wl_list_empty(&wlr_output->modes)) { | 380 | } else if (!wl_list_empty(&wlr_output->modes)) { |
360 | struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output); | 381 | sway_log(SWAY_DEBUG, "Set preferred mode"); |
361 | wlr_output_set_mode(wlr_output, mode); | 382 | struct wlr_output_mode *preferred_mode = |
383 | wlr_output_preferred_mode(wlr_output); | ||
384 | wlr_output_set_mode(wlr_output, preferred_mode); | ||
385 | |||
386 | if (!wlr_output_test(wlr_output)) { | ||
387 | sway_log(SWAY_DEBUG, "Preferred mode rejected, " | ||
388 | "falling back to another mode"); | ||
389 | struct wlr_output_mode *mode; | ||
390 | wl_list_for_each(mode, &wlr_output->modes, link) { | ||
391 | if (mode == preferred_mode) { | ||
392 | continue; | ||
393 | } | ||
394 | |||
395 | wlr_output_set_mode(wlr_output, mode); | ||
396 | if (wlr_output_test(wlr_output)) { | ||
397 | break; | ||
398 | } | ||
399 | } | ||
400 | } | ||
362 | } | 401 | } |
363 | 402 | ||
364 | if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) { | 403 | if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) { |
@@ -367,9 +406,16 @@ static void queue_output_config(struct output_config *oc, | |||
367 | wlr_output_set_subpixel(wlr_output, oc->subpixel); | 406 | wlr_output_set_subpixel(wlr_output, oc->subpixel); |
368 | } | 407 | } |
369 | 408 | ||
409 | enum wl_output_transform tr = WL_OUTPUT_TRANSFORM_NORMAL; | ||
370 | if (oc && oc->transform >= 0) { | 410 | if (oc && oc->transform >= 0) { |
371 | sway_log(SWAY_DEBUG, "Set %s transform to %d", oc->name, oc->transform); | 411 | tr = oc->transform; |
372 | wlr_output_set_transform(wlr_output, oc->transform); | 412 | } else if (wlr_output_is_drm(wlr_output)) { |
413 | tr = wlr_drm_connector_get_panel_orientation(wlr_output); | ||
414 | sway_log(SWAY_DEBUG, "Auto-detected output transform: %d", tr); | ||
415 | } | ||
416 | if (wlr_output->transform != tr) { | ||
417 | sway_log(SWAY_DEBUG, "Set %s transform to %d", oc->name, tr); | ||
418 | wlr_output_set_transform(wlr_output, tr); | ||
373 | } | 419 | } |
374 | 420 | ||
375 | // Apply the scale last before the commit, because the scale auto-detection | 421 | // Apply the scale last before the commit, because the scale auto-detection |
@@ -483,6 +529,8 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) { | |||
483 | // this output came online, and some config items (like map_to_output) are | 529 | // this output came online, and some config items (like map_to_output) are |
484 | // dependent on an output being present. | 530 | // dependent on an output being present. |
485 | input_manager_configure_all_inputs(); | 531 | input_manager_configure_all_inputs(); |
532 | // Reconfigure the cursor images, since the scale may have changed. | ||
533 | input_manager_configure_xcursor(); | ||
486 | return true; | 534 | return true; |
487 | } | 535 | } |
488 | 536 | ||
diff --git a/sway/criteria.c b/sway/criteria.c index 409160c5..d2a5566f 100644 --- a/sway/criteria.c +++ b/sway/criteria.c | |||
@@ -351,7 +351,7 @@ static bool criteria_matches_view(struct criteria *criteria, | |||
351 | } | 351 | } |
352 | 352 | ||
353 | if (criteria->workspace) { | 353 | if (criteria->workspace) { |
354 | struct sway_workspace *ws = view->container->workspace; | 354 | struct sway_workspace *ws = view->container->pending.workspace; |
355 | if (!ws) { | 355 | if (!ws) { |
356 | return false; | 356 | return false; |
357 | } | 357 | } |
@@ -359,7 +359,7 @@ static bool criteria_matches_view(struct criteria *criteria, | |||
359 | switch (criteria->workspace->match_type) { | 359 | switch (criteria->workspace->match_type) { |
360 | case PATTERN_FOCUSED: | 360 | case PATTERN_FOCUSED: |
361 | if (focused && | 361 | if (focused && |
362 | strcmp(ws->name, focused->container->workspace->name)) { | 362 | strcmp(ws->name, focused->container->pending.workspace->name)) { |
363 | return false; | 363 | return false; |
364 | } | 364 | } |
365 | break; | 365 | break; |
diff --git a/sway/desktop/idle_inhibit_v1.c b/sway/desktop/idle_inhibit_v1.c index a5cfd5b2..82353038 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) { | |||
36 | 36 | ||
37 | inhibitor->manager = manager; | 37 | inhibitor->manager = manager; |
38 | inhibitor->mode = INHIBIT_IDLE_APPLICATION; | 38 | inhibitor->mode = INHIBIT_IDLE_APPLICATION; |
39 | inhibitor->view = view_from_wlr_surface(wlr_inhibitor->surface); | 39 | inhibitor->wlr_inhibitor = wlr_inhibitor; |
40 | wl_list_insert(&manager->inhibitors, &inhibitor->link); | 40 | wl_list_insert(&manager->inhibitors, &inhibitor->link); |
41 | 41 | ||
42 | inhibitor->destroy.notify = handle_destroy; | 42 | inhibitor->destroy.notify = handle_destroy; |
@@ -69,8 +69,8 @@ struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_user_inhibitor_for_view( | |||
69 | struct sway_idle_inhibitor_v1 *inhibitor; | 69 | struct sway_idle_inhibitor_v1 *inhibitor; |
70 | wl_list_for_each(inhibitor, &server.idle_inhibit_manager_v1->inhibitors, | 70 | wl_list_for_each(inhibitor, &server.idle_inhibit_manager_v1->inhibitors, |
71 | link) { | 71 | link) { |
72 | if (inhibitor->view == view && | 72 | if (inhibitor->mode != INHIBIT_IDLE_APPLICATION && |
73 | inhibitor->mode != INHIBIT_IDLE_APPLICATION) { | 73 | inhibitor->view == view) { |
74 | return inhibitor; | 74 | return inhibitor; |
75 | } | 75 | } |
76 | } | 76 | } |
@@ -82,8 +82,8 @@ struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_application_inhibitor_for_vi | |||
82 | struct sway_idle_inhibitor_v1 *inhibitor; | 82 | struct sway_idle_inhibitor_v1 *inhibitor; |
83 | wl_list_for_each(inhibitor, &server.idle_inhibit_manager_v1->inhibitors, | 83 | wl_list_for_each(inhibitor, &server.idle_inhibit_manager_v1->inhibitors, |
84 | link) { | 84 | link) { |
85 | if (inhibitor->view == view && | 85 | if (inhibitor->mode == INHIBIT_IDLE_APPLICATION && |
86 | inhibitor->mode == INHIBIT_IDLE_APPLICATION) { | 86 | view_from_wlr_surface(inhibitor->wlr_inhibitor->surface) == view) { |
87 | return inhibitor; | 87 | return inhibitor; |
88 | } | 88 | } |
89 | } | 89 | } |
@@ -104,10 +104,10 @@ void sway_idle_inhibit_v1_user_inhibitor_destroy( | |||
104 | 104 | ||
105 | bool sway_idle_inhibit_v1_is_active(struct sway_idle_inhibitor_v1 *inhibitor) { | 105 | bool sway_idle_inhibit_v1_is_active(struct sway_idle_inhibitor_v1 *inhibitor) { |
106 | switch (inhibitor->mode) { | 106 | switch (inhibitor->mode) { |
107 | case INHIBIT_IDLE_APPLICATION: | 107 | case INHIBIT_IDLE_APPLICATION:; |
108 | // If there is no view associated with the inhibitor, assume visible | 108 | // If there is no view associated with the inhibitor, assume visible |
109 | return !inhibitor->view || !inhibitor->view->container || | 109 | struct sway_view *view = view_from_wlr_surface(inhibitor->wlr_inhibitor->surface); |
110 | view_is_visible(inhibitor->view); | 110 | return !view || !view->container || view_is_visible(view); |
111 | case INHIBIT_IDLE_FOCUS:; | 111 | case INHIBIT_IDLE_FOCUS:; |
112 | struct sway_seat *seat = NULL; | 112 | struct sway_seat *seat = NULL; |
113 | wl_list_for_each(seat, &server.input->seats, link) { | 113 | wl_list_for_each(seat, &server.input->seats, link) { |
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c index d4ca4fb4..7f5a337b 100644 --- a/sway/desktop/layer_shell.c +++ b/sway/desktop/layer_shell.c | |||
@@ -2,7 +2,6 @@ | |||
2 | #include <stdlib.h> | 2 | #include <stdlib.h> |
3 | #include <string.h> | 3 | #include <string.h> |
4 | #include <wayland-server-core.h> | 4 | #include <wayland-server-core.h> |
5 | #include <wlr/types/wlr_box.h> | ||
6 | #include <wlr/types/wlr_layer_shell_v1.h> | 5 | #include <wlr/types/wlr_layer_shell_v1.h> |
7 | #include <wlr/types/wlr_output_damage.h> | 6 | #include <wlr/types/wlr_output_damage.h> |
8 | #include <wlr/types/wlr_output.h> | 7 | #include <wlr/types/wlr_output.h> |
@@ -115,9 +114,10 @@ static void arrange_layer(struct sway_output *output, struct wl_list *list, | |||
115 | // Horizontal axis | 114 | // Horizontal axis |
116 | const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | 115 | const uint32_t both_horiz = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
117 | | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; | 116 | | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; |
118 | if ((state->anchor & both_horiz) && box.width == 0) { | 117 | if (box.width == 0) { |
119 | box.x = bounds.x; | 118 | box.x = bounds.x; |
120 | box.width = bounds.width; | 119 | } else if ((state->anchor & both_horiz) == both_horiz) { |
120 | box.x = bounds.x + ((bounds.width / 2) - (box.width / 2)); | ||
121 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { | 121 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { |
122 | box.x = bounds.x; | 122 | box.x = bounds.x; |
123 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { | 123 | } 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, | |||
128 | // Vertical axis | 128 | // Vertical axis |
129 | const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | 129 | const uint32_t both_vert = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
130 | | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; | 130 | | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; |
131 | if ((state->anchor & both_vert) && box.height == 0) { | 131 | if (box.height == 0) { |
132 | box.y = bounds.y; | 132 | box.y = bounds.y; |
133 | box.height = bounds.height; | 133 | } else if ((state->anchor & both_vert) == both_vert) { |
134 | box.y = bounds.y + ((bounds.height / 2) - (box.height / 2)); | ||
134 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { | 135 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { |
135 | box.y = bounds.y; | 136 | box.y = bounds.y; |
136 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { | 137 | } 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, | |||
139 | box.y = bounds.y + ((bounds.height / 2) - (box.height / 2)); | 140 | box.y = bounds.y + ((bounds.height / 2) - (box.height / 2)); |
140 | } | 141 | } |
141 | // Margin | 142 | // Margin |
142 | if ((state->anchor & both_horiz) == both_horiz) { | 143 | if (box.width == 0) { |
143 | box.x += state->margin.left; | 144 | box.x += state->margin.left; |
144 | box.width -= state->margin.left + state->margin.right; | 145 | box.width = bounds.width - |
146 | (state->margin.left + state->margin.right); | ||
147 | } else if ((state->anchor & both_horiz) == both_horiz) { | ||
148 | // don't apply margins | ||
145 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { | 149 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT)) { |
146 | box.x += state->margin.left; | 150 | box.x += state->margin.left; |
147 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { | 151 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT)) { |
148 | box.x -= state->margin.right; | 152 | box.x -= state->margin.right; |
149 | } | 153 | } |
150 | if ((state->anchor & both_vert) == both_vert) { | 154 | if (box.height == 0) { |
151 | box.y += state->margin.top; | 155 | box.y += state->margin.top; |
152 | box.height -= state->margin.top + state->margin.bottom; | 156 | box.height = bounds.height - |
157 | (state->margin.top + state->margin.bottom); | ||
158 | } else if ((state->anchor & both_vert) == both_vert) { | ||
159 | // don't apply margins | ||
153 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { | 160 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP)) { |
154 | box.y += state->margin.top; | 161 | box.y += state->margin.top; |
155 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { | 162 | } else if ((state->anchor & ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM)) { |
156 | box.y -= state->margin.bottom; | 163 | box.y -= state->margin.bottom; |
157 | } | 164 | } |
158 | if (box.width < 0 || box.height < 0) { | 165 | if (!sway_assert(box.width >= 0 && box.height >= 0, |
159 | // TODO: Bubble up a protocol error? | 166 | "Expected layer surface to have positive size")) { |
160 | wlr_layer_surface_v1_close(layer); | ||
161 | continue; | 167 | continue; |
162 | } | 168 | } |
163 | // Apply | 169 | // Apply |
@@ -191,7 +197,7 @@ void arrange_layers(struct sway_output *output) { | |||
191 | arrange_output(output); | 197 | arrange_output(output); |
192 | } | 198 | } |
193 | 199 | ||
194 | // Arrange non-exlusive surfaces from top->bottom | 200 | // Arrange non-exclusive surfaces from top->bottom |
195 | arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], | 201 | arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], |
196 | &usable_area, false); | 202 | &usable_area, false); |
197 | arrange_layer(output, &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_TOP], | 203 | 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) { | |||
277 | } | 283 | } |
278 | 284 | ||
279 | sway_layer->layer_surface->output = NULL; | 285 | sway_layer->layer_surface->output = NULL; |
280 | wlr_layer_surface_v1_close(sway_layer->layer_surface); | 286 | wlr_layer_surface_v1_destroy(sway_layer->layer_surface); |
281 | } | 287 | } |
282 | 288 | ||
283 | static void handle_surface_commit(struct wl_listener *listener, void *data) { | 289 | 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) { | |||
290 | } | 296 | } |
291 | 297 | ||
292 | struct sway_output *output = wlr_output->data; | 298 | struct sway_output *output = wlr_output->data; |
293 | struct wlr_box old_geo = layer->geo; | 299 | struct wlr_box old_extent = layer->extent; |
294 | arrange_layers(output); | 300 | |
295 | 301 | bool layer_changed = false; | |
296 | bool geo_changed = | 302 | if (layer_surface->current.committed != 0 |
297 | memcmp(&old_geo, &layer->geo, sizeof(struct wlr_box)) != 0; | 303 | || layer->mapped != layer_surface->mapped) { |
298 | bool layer_changed = layer->layer != layer_surface->current.layer; | 304 | layer->mapped = layer_surface->mapped; |
299 | if (layer_changed) { | 305 | layer_changed = layer->layer != layer_surface->current.layer; |
300 | wl_list_remove(&layer->link); | 306 | if (layer_changed) { |
301 | wl_list_insert(&output->layers[layer_surface->current.layer], | 307 | wl_list_remove(&layer->link); |
302 | &layer->link); | 308 | wl_list_insert(&output->layers[layer_surface->current.layer], |
303 | layer->layer = layer_surface->current.layer; | 309 | &layer->link); |
310 | layer->layer = layer_surface->current.layer; | ||
311 | } | ||
312 | arrange_layers(output); | ||
304 | } | 313 | } |
305 | if (geo_changed || layer_changed) { | 314 | |
306 | output_damage_surface(output, old_geo.x, old_geo.y, | 315 | wlr_surface_get_extends(layer_surface->surface, &layer->extent); |
307 | layer_surface->surface, true); | 316 | layer->extent.x += layer->geo.x; |
317 | layer->extent.y += layer->geo.y; | ||
318 | |||
319 | bool extent_changed = | ||
320 | memcmp(&old_extent, &layer->extent, sizeof(struct wlr_box)) != 0; | ||
321 | if (extent_changed || layer_changed) { | ||
322 | output_damage_box(output, &old_extent); | ||
308 | output_damage_surface(output, layer->geo.x, layer->geo.y, | 323 | output_damage_surface(output, layer->geo.x, layer->geo.y, |
309 | layer_surface->surface, true); | 324 | layer_surface->surface, true); |
310 | } else { | 325 | } else { |
@@ -429,7 +444,7 @@ static struct sway_layer_subsurface *create_subsurface( | |||
429 | struct wlr_subsurface *wlr_subsurface, | 444 | struct wlr_subsurface *wlr_subsurface, |
430 | struct sway_layer_surface *layer_surface) { | 445 | struct sway_layer_surface *layer_surface) { |
431 | struct sway_layer_subsurface *subsurface = | 446 | struct sway_layer_subsurface *subsurface = |
432 | calloc(1, sizeof(struct sway_layer_surface)); | 447 | calloc(1, sizeof(struct sway_layer_subsurface)); |
433 | if (subsurface == NULL) { | 448 | if (subsurface == NULL) { |
434 | return NULL; | 449 | return NULL; |
435 | } | 450 | } |
@@ -468,8 +483,8 @@ static struct sway_layer_surface *popup_get_layer( | |||
468 | static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) { | 483 | static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) { |
469 | struct wlr_xdg_popup *popup = layer_popup->wlr_popup; | 484 | struct wlr_xdg_popup *popup = layer_popup->wlr_popup; |
470 | struct wlr_surface *surface = popup->base->surface; | 485 | struct wlr_surface *surface = popup->base->surface; |
471 | int popup_sx = popup->geometry.x - popup->base->geometry.x; | 486 | int popup_sx = popup->geometry.x - popup->base->current.geometry.x; |
472 | int popup_sy = popup->geometry.y - popup->base->geometry.y; | 487 | int popup_sy = popup->geometry.y - popup->base->current.geometry.y; |
473 | int ox = popup_sx, oy = popup_sy; | 488 | int ox = popup_sx, oy = popup_sy; |
474 | struct sway_layer_surface *layer; | 489 | struct sway_layer_surface *layer; |
475 | while (true) { | 490 | while (true) { |
@@ -590,14 +605,14 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { | |||
590 | sway_log(SWAY_DEBUG, "new layer surface: namespace %s layer %d anchor %" PRIu32 | 605 | sway_log(SWAY_DEBUG, "new layer surface: namespace %s layer %d anchor %" PRIu32 |
591 | " size %" PRIu32 "x%" PRIu32 " margin %" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",", | 606 | " size %" PRIu32 "x%" PRIu32 " margin %" PRIu32 ",%" PRIu32 ",%" PRIu32 ",%" PRIu32 ",", |
592 | layer_surface->namespace, | 607 | layer_surface->namespace, |
593 | layer_surface->client_pending.layer, | 608 | layer_surface->pending.layer, |
594 | layer_surface->client_pending.anchor, | 609 | layer_surface->pending.anchor, |
595 | layer_surface->client_pending.desired_width, | 610 | layer_surface->pending.desired_width, |
596 | layer_surface->client_pending.desired_height, | 611 | layer_surface->pending.desired_height, |
597 | layer_surface->client_pending.margin.top, | 612 | layer_surface->pending.margin.top, |
598 | layer_surface->client_pending.margin.right, | 613 | layer_surface->pending.margin.right, |
599 | layer_surface->client_pending.margin.bottom, | 614 | layer_surface->pending.margin.bottom, |
600 | layer_surface->client_pending.margin.left); | 615 | layer_surface->pending.margin.left); |
601 | 616 | ||
602 | if (!layer_surface->output) { | 617 | if (!layer_surface->output) { |
603 | // Assign last active output | 618 | // Assign last active output |
@@ -614,7 +629,7 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { | |||
614 | sway_log(SWAY_ERROR, | 629 | sway_log(SWAY_ERROR, |
615 | "no output to auto-assign layer surface '%s' to", | 630 | "no output to auto-assign layer surface '%s' to", |
616 | layer_surface->namespace); | 631 | layer_surface->namespace); |
617 | wlr_layer_surface_v1_close(layer_surface); | 632 | wlr_layer_surface_v1_destroy(layer_surface); |
618 | return; | 633 | return; |
619 | } | 634 | } |
620 | output = root->outputs->items[0]; | 635 | output = root->outputs->items[0]; |
@@ -651,13 +666,13 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) { | |||
651 | sway_layer->output_destroy.notify = handle_output_destroy; | 666 | sway_layer->output_destroy.notify = handle_output_destroy; |
652 | wl_signal_add(&output->events.destroy, &sway_layer->output_destroy); | 667 | wl_signal_add(&output->events.destroy, &sway_layer->output_destroy); |
653 | 668 | ||
654 | wl_list_insert(&output->layers[layer_surface->client_pending.layer], | 669 | wl_list_insert(&output->layers[layer_surface->pending.layer], |
655 | &sway_layer->link); | 670 | &sway_layer->link); |
656 | 671 | ||
657 | // Temporarily set the layer's current state to client_pending | 672 | // Temporarily set the layer's current state to pending |
658 | // So that we can easily arrange it | 673 | // So that we can easily arrange it |
659 | struct wlr_layer_surface_v1_state old_state = layer_surface->current; | 674 | struct wlr_layer_surface_v1_state old_state = layer_surface->current; |
660 | layer_surface->current = layer_surface->client_pending; | 675 | layer_surface->current = layer_surface->pending; |
661 | arrange_layers(output); | 676 | arrange_layers(output); |
662 | layer_surface->current = old_state; | 677 | layer_surface->current = old_state; |
663 | } | 678 | } |
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index 5edc8f96..8cdd47f5 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -4,9 +4,10 @@ | |||
4 | #include <strings.h> | 4 | #include <strings.h> |
5 | #include <time.h> | 5 | #include <time.h> |
6 | #include <wayland-server-core.h> | 6 | #include <wayland-server-core.h> |
7 | #include <wlr/backend/drm.h> | ||
7 | #include <wlr/render/wlr_renderer.h> | 8 | #include <wlr/render/wlr_renderer.h> |
8 | #include <wlr/types/wlr_box.h> | ||
9 | #include <wlr/types/wlr_buffer.h> | 9 | #include <wlr/types/wlr_buffer.h> |
10 | #include <wlr/types/wlr_drm_lease_v1.h> | ||
10 | #include <wlr/types/wlr_matrix.h> | 11 | #include <wlr/types/wlr_matrix.h> |
11 | #include <wlr/types/wlr_output_damage.h> | 12 | #include <wlr/types/wlr_output_damage.h> |
12 | #include <wlr/types/wlr_output_layout.h> | 13 | #include <wlr/types/wlr_output_layout.h> |
@@ -56,26 +57,6 @@ struct sway_output *all_output_by_name_or_id(const char *name_or_id) { | |||
56 | return NULL; | 57 | return NULL; |
57 | } | 58 | } |
58 | 59 | ||
59 | /** | ||
60 | * Rotate a child's position relative to a parent. The parent size is (pw, ph), | ||
61 | * the child position is (*sx, *sy) and its size is (sw, sh). | ||
62 | */ | ||
63 | static void rotate_child_position(double *sx, double *sy, double sw, double sh, | ||
64 | double pw, double ph, float rotation) { | ||
65 | if (rotation == 0.0f) { | ||
66 | return; | ||
67 | } | ||
68 | |||
69 | // Coordinates relative to the center of the subsurface | ||
70 | double ox = *sx - pw/2 + sw/2, | ||
71 | oy = *sy - ph/2 + sh/2; | ||
72 | // Rotated coordinates | ||
73 | double rx = cos(-rotation)*ox - sin(-rotation)*oy, | ||
74 | ry = cos(-rotation)*oy + sin(-rotation)*ox; | ||
75 | *sx = rx + pw/2 - sw/2; | ||
76 | *sy = ry + ph/2 - sh/2; | ||
77 | } | ||
78 | |||
79 | struct surface_iterator_data { | 60 | struct surface_iterator_data { |
80 | sway_surface_iterator_func_t user_iterator; | 61 | sway_surface_iterator_func_t user_iterator; |
81 | void *user_data; | 62 | void *user_data; |
@@ -84,7 +65,6 @@ struct surface_iterator_data { | |||
84 | struct sway_view *view; | 65 | struct sway_view *view; |
85 | double ox, oy; | 66 | double ox, oy; |
86 | int width, height; | 67 | int width, height; |
87 | float rotation; | ||
88 | }; | 68 | }; |
89 | 69 | ||
90 | static bool get_surface_box(struct surface_iterator_data *data, | 70 | static bool get_surface_box(struct surface_iterator_data *data, |
@@ -99,14 +79,9 @@ static bool get_surface_box(struct surface_iterator_data *data, | |||
99 | int sw = surface->current.width; | 79 | int sw = surface->current.width; |
100 | int sh = surface->current.height; | 80 | int sh = surface->current.height; |
101 | 81 | ||
102 | double _sx = sx + surface->sx; | ||
103 | double _sy = sy + surface->sy; | ||
104 | rotate_child_position(&_sx, &_sy, sw, sh, data->width, data->height, | ||
105 | data->rotation); | ||
106 | |||
107 | struct wlr_box box = { | 82 | struct wlr_box box = { |
108 | .x = data->ox + _sx, | 83 | .x = floor(data->ox + sx), |
109 | .y = data->oy + _sy, | 84 | .y = floor(data->oy + sy), |
110 | .width = sw, | 85 | .width = sw, |
111 | .height = sh, | 86 | .height = sh, |
112 | }; | 87 | }; |
@@ -114,16 +89,13 @@ static bool get_surface_box(struct surface_iterator_data *data, | |||
114 | memcpy(surface_box, &box, sizeof(struct wlr_box)); | 89 | memcpy(surface_box, &box, sizeof(struct wlr_box)); |
115 | } | 90 | } |
116 | 91 | ||
117 | struct wlr_box rotated_box; | ||
118 | wlr_box_rotated_bounds(&rotated_box, &box, data->rotation); | ||
119 | |||
120 | struct wlr_box output_box = { | 92 | struct wlr_box output_box = { |
121 | .width = output->width, | 93 | .width = output->width, |
122 | .height = output->height, | 94 | .height = output->height, |
123 | }; | 95 | }; |
124 | 96 | ||
125 | struct wlr_box intersection; | 97 | struct wlr_box intersection; |
126 | return wlr_box_intersection(&intersection, &output_box, &rotated_box); | 98 | return wlr_box_intersection(&intersection, &output_box, &box); |
127 | } | 99 | } |
128 | 100 | ||
129 | static void output_for_each_surface_iterator(struct wlr_surface *surface, | 101 | 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, | |||
136 | return; | 108 | return; |
137 | } | 109 | } |
138 | 110 | ||
139 | data->user_iterator(data->output, data->view, surface, &box, data->rotation, | 111 | data->user_iterator(data->output, data->view, surface, &box, |
140 | data->user_data); | 112 | data->user_data); |
141 | } | 113 | } |
142 | 114 | ||
@@ -152,7 +124,6 @@ void output_surface_for_each_surface(struct sway_output *output, | |||
152 | .oy = oy, | 124 | .oy = oy, |
153 | .width = surface->current.width, | 125 | .width = surface->current.width, |
154 | .height = surface->current.height, | 126 | .height = surface->current.height, |
155 | .rotation = 0, | ||
156 | }; | 127 | }; |
157 | 128 | ||
158 | wlr_surface_for_each_surface(surface, | 129 | wlr_surface_for_each_surface(surface, |
@@ -173,7 +144,6 @@ void output_view_for_each_surface(struct sway_output *output, | |||
173 | - view->geometry.y, | 144 | - view->geometry.y, |
174 | .width = view->container->current.content_width, | 145 | .width = view->container->current.content_width, |
175 | .height = view->container->current.content_height, | 146 | .height = view->container->current.content_height, |
176 | .rotation = 0, // TODO | ||
177 | }; | 147 | }; |
178 | 148 | ||
179 | view_for_each_surface(view, output_for_each_surface_iterator, &data); | 149 | view_for_each_surface(view, output_for_each_surface_iterator, &data); |
@@ -193,7 +163,6 @@ void output_view_for_each_popup_surface(struct sway_output *output, | |||
193 | - view->geometry.y, | 163 | - view->geometry.y, |
194 | .width = view->container->current.content_width, | 164 | .width = view->container->current.content_width, |
195 | .height = view->container->current.content_height, | 165 | .height = view->container->current.content_height, |
196 | .rotation = 0, // TODO | ||
197 | }; | 166 | }; |
198 | 167 | ||
199 | view_for_each_popup_surface(view, output_for_each_surface_iterator, &data); | 168 | view_for_each_popup_surface(view, output_for_each_surface_iterator, &data); |
@@ -206,40 +175,19 @@ void output_layer_for_each_surface(struct sway_output *output, | |||
206 | wl_list_for_each(layer_surface, layer_surfaces, link) { | 175 | wl_list_for_each(layer_surface, layer_surfaces, link) { |
207 | struct wlr_layer_surface_v1 *wlr_layer_surface_v1 = | 176 | struct wlr_layer_surface_v1 *wlr_layer_surface_v1 = |
208 | layer_surface->layer_surface; | 177 | layer_surface->layer_surface; |
209 | output_surface_for_each_surface(output, wlr_layer_surface_v1->surface, | 178 | struct wlr_surface *surface = wlr_layer_surface_v1->surface; |
210 | layer_surface->geo.x, layer_surface->geo.y, iterator, | 179 | struct surface_iterator_data data = { |
211 | user_data); | 180 | .user_iterator = iterator, |
212 | 181 | .user_data = user_data, | |
213 | struct wlr_xdg_popup *state; | 182 | .output = output, |
214 | wl_list_for_each(state, &wlr_layer_surface_v1->popups, link) { | 183 | .view = NULL, |
215 | struct wlr_xdg_surface *popup = state->base; | 184 | .ox = layer_surface->geo.x, |
216 | if (!popup->configured) { | 185 | .oy = layer_surface->geo.y, |
217 | continue; | 186 | .width = surface->current.width, |
218 | } | 187 | .height = surface->current.height, |
219 | 188 | }; | |
220 | double popup_sx, popup_sy; | 189 | wlr_layer_surface_v1_for_each_surface(wlr_layer_surface_v1, |
221 | popup_sx = layer_surface->geo.x + | 190 | output_for_each_surface_iterator, &data); |
222 | popup->popup->geometry.x - popup->geometry.x; | ||
223 | popup_sy = layer_surface->geo.y + | ||
224 | popup->popup->geometry.y - popup->geometry.y; | ||
225 | |||
226 | struct wlr_surface *surface = popup->surface; | ||
227 | |||
228 | struct surface_iterator_data data = { | ||
229 | .user_iterator = iterator, | ||
230 | .user_data = user_data, | ||
231 | .output = output, | ||
232 | .view = NULL, | ||
233 | .ox = popup_sx, | ||
234 | .oy = popup_sy, | ||
235 | .width = surface->current.width, | ||
236 | .height = surface->current.height, | ||
237 | .rotation = 0, | ||
238 | }; | ||
239 | |||
240 | wlr_xdg_surface_for_each_surface( | ||
241 | popup, output_for_each_surface_iterator, &data); | ||
242 | } | ||
243 | } | 191 | } |
244 | } | 192 | } |
245 | 193 | ||
@@ -264,37 +212,19 @@ void output_layer_for_each_popup_surface(struct sway_output *output, | |||
264 | wl_list_for_each(layer_surface, layer_surfaces, link) { | 212 | wl_list_for_each(layer_surface, layer_surfaces, link) { |
265 | struct wlr_layer_surface_v1 *wlr_layer_surface_v1 = | 213 | struct wlr_layer_surface_v1 *wlr_layer_surface_v1 = |
266 | layer_surface->layer_surface; | 214 | layer_surface->layer_surface; |
267 | 215 | struct wlr_surface *surface = wlr_layer_surface_v1->surface; | |
268 | struct wlr_xdg_popup *state; | 216 | struct surface_iterator_data data = { |
269 | wl_list_for_each(state, &wlr_layer_surface_v1->popups, link) { | 217 | .user_iterator = iterator, |
270 | struct wlr_xdg_surface *popup = state->base; | 218 | .user_data = user_data, |
271 | if (!popup->configured) { | 219 | .output = output, |
272 | continue; | 220 | .view = NULL, |
273 | } | 221 | .ox = layer_surface->geo.x, |
274 | 222 | .oy = layer_surface->geo.y, | |
275 | double popup_sx, popup_sy; | 223 | .width = surface->current.width, |
276 | popup_sx = layer_surface->geo.x + | 224 | .height = surface->current.height, |
277 | popup->popup->geometry.x - popup->geometry.x; | 225 | }; |
278 | popup_sy = layer_surface->geo.y + | 226 | wlr_layer_surface_v1_for_each_popup_surface(wlr_layer_surface_v1, |
279 | popup->popup->geometry.y - popup->geometry.y; | 227 | output_for_each_surface_iterator, &data); |
280 | |||
281 | struct wlr_surface *surface = popup->surface; | ||
282 | |||
283 | struct surface_iterator_data data = { | ||
284 | .user_iterator = iterator, | ||
285 | .user_data = user_data, | ||
286 | .output = output, | ||
287 | .view = NULL, | ||
288 | .ox = popup_sx, | ||
289 | .oy = popup_sy, | ||
290 | .width = surface->current.width, | ||
291 | .height = surface->current.height, | ||
292 | .rotation = 0, | ||
293 | }; | ||
294 | |||
295 | wlr_xdg_surface_for_each_surface( | ||
296 | popup, output_for_each_surface_iterator, &data); | ||
297 | } | ||
298 | } | 228 | } |
299 | } | 229 | } |
300 | 230 | ||
@@ -463,9 +393,9 @@ struct send_frame_done_data { | |||
463 | int msec_until_refresh; | 393 | int msec_until_refresh; |
464 | }; | 394 | }; |
465 | 395 | ||
466 | static void send_frame_done_iterator(struct sway_output *output, struct sway_view *view, | 396 | static void send_frame_done_iterator(struct sway_output *output, |
467 | struct wlr_surface *surface, struct wlr_box *box, float rotation, | 397 | struct sway_view *view, struct wlr_surface *surface, |
468 | void *user_data) { | 398 | struct wlr_box *box, void *user_data) { |
469 | int view_max_render_time = 0; | 399 | int view_max_render_time = 0; |
470 | if (view != NULL) { | 400 | if (view != NULL) { |
471 | view_max_render_time = view->max_render_time; | 401 | 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 | |||
488 | output_for_each_surface(output, send_frame_done_iterator, data); | 418 | output_for_each_surface(output, send_frame_done_iterator, data); |
489 | } | 419 | } |
490 | 420 | ||
491 | static void count_surface_iterator(struct sway_output *output, struct sway_view *view, | 421 | static void count_surface_iterator(struct sway_output *output, |
492 | struct wlr_surface *surface, struct wlr_box *_box, float rotation, | 422 | struct sway_view *view, struct wlr_surface *surface, |
493 | void *data) { | 423 | struct wlr_box *box, void *data) { |
494 | size_t *n = data; | 424 | size_t *n = data; |
495 | (*n)++; | 425 | (*n)++; |
496 | } | 426 | } |
@@ -577,7 +507,7 @@ static int output_repaint_timer_handler(void *data) { | |||
577 | fullscreen_con = workspace->current.fullscreen; | 507 | fullscreen_con = workspace->current.fullscreen; |
578 | } | 508 | } |
579 | 509 | ||
580 | if (fullscreen_con && fullscreen_con->view) { | 510 | if (fullscreen_con && fullscreen_con->view && !debug.noscanout) { |
581 | // Try to scan-out the fullscreen view | 511 | // Try to scan-out the fullscreen view |
582 | static bool last_scanned_out = false; | 512 | static bool last_scanned_out = false; |
583 | bool scanned_out = | 513 | bool scanned_out = |
@@ -590,6 +520,7 @@ static int output_repaint_timer_handler(void *data) { | |||
590 | if (last_scanned_out && !scanned_out) { | 520 | if (last_scanned_out && !scanned_out) { |
591 | sway_log(SWAY_DEBUG, "Stopping fullscreen view scan out on %s", | 521 | sway_log(SWAY_DEBUG, "Stopping fullscreen view scan out on %s", |
592 | output->wlr_output->name); | 522 | output->wlr_output->name); |
523 | output_damage_whole(output); | ||
593 | } | 524 | } |
594 | last_scanned_out = scanned_out; | 525 | last_scanned_out = scanned_out; |
595 | 526 | ||
@@ -693,18 +624,15 @@ void output_damage_whole(struct sway_output *output) { | |||
693 | } | 624 | } |
694 | } | 625 | } |
695 | 626 | ||
696 | static void damage_surface_iterator(struct sway_output *output, struct sway_view *view, | 627 | static void damage_surface_iterator(struct sway_output *output, |
697 | struct wlr_surface *surface, struct wlr_box *_box, float rotation, | 628 | struct sway_view *view, struct wlr_surface *surface, |
698 | void *_data) { | 629 | struct wlr_box *_box, void *_data) { |
699 | bool *data = _data; | 630 | bool *data = _data; |
700 | bool whole = *data; | 631 | bool whole = *data; |
701 | 632 | ||
702 | struct wlr_box box = *_box; | 633 | struct wlr_box box = *_box; |
703 | scale_box(&box, output->wlr_output->scale); | 634 | scale_box(&box, output->wlr_output->scale); |
704 | 635 | ||
705 | int center_x = box.x + box.width/2; | ||
706 | int center_y = box.y + box.height/2; | ||
707 | |||
708 | if (pixman_region32_not_empty(&surface->buffer_damage)) { | 636 | if (pixman_region32_not_empty(&surface->buffer_damage)) { |
709 | pixman_region32_t damage; | 637 | pixman_region32_t damage; |
710 | pixman_region32_init(&damage); | 638 | pixman_region32_init(&damage); |
@@ -717,14 +645,11 @@ static void damage_surface_iterator(struct sway_output *output, struct sway_view | |||
717 | ceil(output->wlr_output->scale) - surface->current.scale); | 645 | ceil(output->wlr_output->scale) - surface->current.scale); |
718 | } | 646 | } |
719 | pixman_region32_translate(&damage, box.x, box.y); | 647 | pixman_region32_translate(&damage, box.x, box.y); |
720 | wlr_region_rotated_bounds(&damage, &damage, rotation, | ||
721 | center_x, center_y); | ||
722 | wlr_output_damage_add(output->damage, &damage); | 648 | wlr_output_damage_add(output->damage, &damage); |
723 | pixman_region32_fini(&damage); | 649 | pixman_region32_fini(&damage); |
724 | } | 650 | } |
725 | 651 | ||
726 | if (whole) { | 652 | if (whole) { |
727 | wlr_box_rotated_bounds(&box, &box, rotation); | ||
728 | wlr_output_damage_add_box(output->damage, &box); | 653 | wlr_output_damage_add_box(output->damage, &box); |
729 | } | 654 | } |
730 | 655 | ||
@@ -816,7 +741,7 @@ static void update_output_manager_config(struct sway_server *server) { | |||
816 | struct wlr_box *output_box = wlr_output_layout_get_box( | 741 | struct wlr_box *output_box = wlr_output_layout_get_box( |
817 | root->output_layout, output->wlr_output); | 742 | root->output_layout, output->wlr_output); |
818 | // We mark the output enabled even if it is switched off by DPMS | 743 | // We mark the output enabled even if it is switched off by DPMS |
819 | config_head->state.enabled = output->enabled; | 744 | config_head->state.enabled = output->current_mode != NULL && output->enabled; |
820 | config_head->state.mode = output->current_mode; | 745 | config_head->state.mode = output->current_mode; |
821 | if (output_box) { | 746 | if (output_box) { |
822 | config_head->state.x = output_box->x; | 747 | config_head->state.x = output_box->x; |
@@ -913,7 +838,17 @@ static void handle_present(struct wl_listener *listener, void *data) { | |||
913 | void handle_new_output(struct wl_listener *listener, void *data) { | 838 | void handle_new_output(struct wl_listener *listener, void *data) { |
914 | struct sway_server *server = wl_container_of(listener, server, new_output); | 839 | struct sway_server *server = wl_container_of(listener, server, new_output); |
915 | struct wlr_output *wlr_output = data; | 840 | struct wlr_output *wlr_output = data; |
916 | sway_log(SWAY_DEBUG, "New output %p: %s", wlr_output, wlr_output->name); | 841 | sway_log(SWAY_DEBUG, "New output %p: %s (non-desktop: %d)", |
842 | wlr_output, wlr_output->name, wlr_output->non_desktop); | ||
843 | |||
844 | if (wlr_output->non_desktop) { | ||
845 | sway_log(SWAY_DEBUG, "Not configuring non-desktop output"); | ||
846 | if (server->drm_lease_manager) { | ||
847 | wlr_drm_lease_v1_manager_offer_output(server->drm_lease_manager, | ||
848 | wlr_output); | ||
849 | } | ||
850 | return; | ||
851 | } | ||
917 | 852 | ||
918 | struct sway_output *output = output_create(wlr_output); | 853 | struct sway_output *output = output_create(wlr_output); |
919 | if (!output) { | 854 | if (!output) { |
diff --git a/sway/desktop/render.c b/sway/desktop/render.c index bd85282c..17fc8f6f 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c | |||
@@ -7,7 +7,6 @@ | |||
7 | #include <wayland-server-core.h> | 7 | #include <wayland-server-core.h> |
8 | #include <wlr/render/gles2.h> | 8 | #include <wlr/render/gles2.h> |
9 | #include <wlr/render/wlr_renderer.h> | 9 | #include <wlr/render/wlr_renderer.h> |
10 | #include <wlr/types/wlr_box.h> | ||
11 | #include <wlr/types/wlr_buffer.h> | 10 | #include <wlr/types/wlr_buffer.h> |
12 | #include <wlr/types/wlr_matrix.h> | 11 | #include <wlr/types/wlr_matrix.h> |
13 | #include <wlr/types/wlr_output_damage.h> | 12 | #include <wlr/types/wlr_output_damage.h> |
@@ -32,6 +31,7 @@ | |||
32 | struct render_data { | 31 | struct render_data { |
33 | pixman_region32_t *damage; | 32 | pixman_region32_t *damage; |
34 | float alpha; | 33 | float alpha; |
34 | struct wlr_box *clip_box; | ||
35 | }; | 35 | }; |
36 | 36 | ||
37 | /** | 37 | /** |
@@ -104,9 +104,6 @@ static void render_texture(struct wlr_output *wlr_output, | |||
104 | wlr_backend_get_renderer(wlr_output->backend); | 104 | wlr_backend_get_renderer(wlr_output->backend); |
105 | struct sway_output *output = wlr_output->data; | 105 | struct sway_output *output = wlr_output->data; |
106 | 106 | ||
107 | struct wlr_gles2_texture_attribs attribs; | ||
108 | wlr_gles2_texture_get_attribs(texture, &attribs); | ||
109 | |||
110 | pixman_region32_t damage; | 107 | pixman_region32_t damage; |
111 | pixman_region32_init(&damage); | 108 | pixman_region32_init(&damage); |
112 | pixman_region32_union_rect(&damage, &damage, dst_box->x, dst_box->y, | 109 | pixman_region32_union_rect(&damage, &damage, dst_box->x, dst_box->y, |
@@ -133,9 +130,9 @@ damage_finish: | |||
133 | pixman_region32_fini(&damage); | 130 | pixman_region32_fini(&damage); |
134 | } | 131 | } |
135 | 132 | ||
136 | static void render_surface_iterator(struct sway_output *output, struct sway_view *view, | 133 | static void render_surface_iterator(struct sway_output *output, |
137 | struct wlr_surface *surface, struct wlr_box *_box, float rotation, | 134 | struct sway_view *view, struct wlr_surface *surface, |
138 | void *_data) { | 135 | struct wlr_box *_box, void *_data) { |
139 | struct render_data *data = _data; | 136 | struct render_data *data = _data; |
140 | struct wlr_output *wlr_output = output->wlr_output; | 137 | struct wlr_output *wlr_output = output->wlr_output; |
141 | pixman_region32_t *output_damage = data->damage; | 138 | pixman_region32_t *output_damage = data->damage; |
@@ -149,15 +146,23 @@ static void render_surface_iterator(struct sway_output *output, struct sway_view | |||
149 | struct wlr_fbox src_box; | 146 | struct wlr_fbox src_box; |
150 | wlr_surface_get_buffer_source_box(surface, &src_box); | 147 | wlr_surface_get_buffer_source_box(surface, &src_box); |
151 | 148 | ||
152 | struct wlr_box dst_box = *_box; | 149 | struct wlr_box proj_box = *_box; |
153 | scale_box(&dst_box, wlr_output->scale); | 150 | scale_box(&proj_box, wlr_output->scale); |
154 | 151 | ||
155 | float matrix[9]; | 152 | float matrix[9]; |
156 | enum wl_output_transform transform = | 153 | enum wl_output_transform transform = |
157 | wlr_output_transform_invert(surface->current.transform); | 154 | wlr_output_transform_invert(surface->current.transform); |
158 | wlr_matrix_project_box(matrix, &dst_box, transform, rotation, | 155 | wlr_matrix_project_box(matrix, &proj_box, transform, 0.0, |
159 | wlr_output->transform_matrix); | 156 | wlr_output->transform_matrix); |
160 | 157 | ||
158 | struct wlr_box dst_box = *_box; | ||
159 | struct wlr_box *clip_box = data->clip_box; | ||
160 | if (clip_box != NULL) { | ||
161 | dst_box.width = fmin(dst_box.width, clip_box->width); | ||
162 | dst_box.height = fmin(dst_box.height, clip_box->height); | ||
163 | } | ||
164 | scale_box(&dst_box, wlr_output->scale); | ||
165 | |||
161 | render_texture(wlr_output, output_damage, texture, | 166 | render_texture(wlr_output, output_damage, texture, |
162 | &src_box, &dst_box, matrix, alpha); | 167 | &src_box, &dst_box, matrix, alpha); |
163 | 168 | ||
@@ -256,6 +261,14 @@ static void render_view_toplevels(struct sway_view *view, | |||
256 | .damage = damage, | 261 | .damage = damage, |
257 | .alpha = alpha, | 262 | .alpha = alpha, |
258 | }; | 263 | }; |
264 | struct wlr_box clip_box; | ||
265 | if (!container_is_current_floating(view->container)) { | ||
266 | // As we pass the geometry offsets to the surface iterator, we will | ||
267 | // need to account for the offsets in the clip dimensions. | ||
268 | clip_box.width = view->container->current.content_width + view->geometry.x; | ||
269 | clip_box.height = view->container->current.content_height + view->geometry.y; | ||
270 | data.clip_box = &clip_box; | ||
271 | } | ||
259 | // Render all toplevels without descending into popups | 272 | // Render all toplevels without descending into popups |
260 | double ox = view->container->surface_x - | 273 | double ox = view->container->surface_x - |
261 | output->lx - view->geometry.x; | 274 | output->lx - view->geometry.x; |
@@ -282,17 +295,18 @@ static void render_saved_view(struct sway_view *view, | |||
282 | if (wl_list_empty(&view->saved_buffers)) { | 295 | if (wl_list_empty(&view->saved_buffers)) { |
283 | return; | 296 | return; |
284 | } | 297 | } |
298 | |||
299 | bool floating = container_is_current_floating(view->container); | ||
300 | |||
285 | struct sway_saved_buffer *saved_buf; | 301 | struct sway_saved_buffer *saved_buf; |
286 | wl_list_for_each(saved_buf, &view->saved_buffers, link) { | 302 | wl_list_for_each(saved_buf, &view->saved_buffers, link) { |
287 | if (!saved_buf->buffer->texture) { | 303 | if (!saved_buf->buffer->texture) { |
288 | continue; | 304 | continue; |
289 | } | 305 | } |
290 | 306 | ||
291 | struct wlr_box box = { | 307 | struct wlr_box proj_box = { |
292 | .x = view->container->surface_x - output->lx - | 308 | .x = saved_buf->x - view->saved_geometry.x - output->lx, |
293 | view->saved_geometry.x + saved_buf->x, | 309 | .y = saved_buf->y - view->saved_geometry.y - output->ly, |
294 | .y = view->container->surface_y - output->ly - | ||
295 | view->saved_geometry.y + saved_buf->y, | ||
296 | .width = saved_buf->width, | 310 | .width = saved_buf->width, |
297 | .height = saved_buf->height, | 311 | .height = saved_buf->height, |
298 | }; | 312 | }; |
@@ -303,20 +317,31 @@ static void render_saved_view(struct sway_view *view, | |||
303 | }; | 317 | }; |
304 | 318 | ||
305 | struct wlr_box intersection; | 319 | struct wlr_box intersection; |
306 | bool intersects = wlr_box_intersection(&intersection, &output_box, &box); | 320 | bool intersects = wlr_box_intersection(&intersection, &output_box, &proj_box); |
307 | if (!intersects) { | 321 | if (!intersects) { |
308 | continue; | 322 | continue; |
309 | } | 323 | } |
310 | 324 | ||
311 | scale_box(&box, wlr_output->scale); | 325 | struct wlr_box dst_box = proj_box; |
326 | scale_box(&proj_box, wlr_output->scale); | ||
312 | 327 | ||
313 | float matrix[9]; | 328 | float matrix[9]; |
314 | enum wl_output_transform transform = wlr_output_transform_invert(saved_buf->transform); | 329 | enum wl_output_transform transform = wlr_output_transform_invert(saved_buf->transform); |
315 | wlr_matrix_project_box(matrix, &box, transform, 0, | 330 | wlr_matrix_project_box(matrix, &proj_box, transform, 0, |
316 | wlr_output->transform_matrix); | 331 | wlr_output->transform_matrix); |
317 | 332 | ||
333 | if (!floating) { | ||
334 | dst_box.width = fmin(dst_box.width, | ||
335 | view->container->current.content_width - | ||
336 | (saved_buf->x - view->container->current.content_x) + view->saved_geometry.x); | ||
337 | dst_box.height = fmin(dst_box.height, | ||
338 | view->container->current.content_height - | ||
339 | (saved_buf->y - view->container->current.content_y) + view->saved_geometry.y); | ||
340 | } | ||
341 | scale_box(&dst_box, wlr_output->scale); | ||
342 | |||
318 | render_texture(wlr_output, damage, saved_buf->buffer->texture, | 343 | render_texture(wlr_output, damage, saved_buf->buffer->texture, |
319 | &saved_buf->source_box, &box, matrix, alpha); | 344 | &saved_buf->source_box, &dst_box, matrix, alpha); |
320 | } | 345 | } |
321 | 346 | ||
322 | // FIXME: we should set the surface that this saved buffer originates from | 347 | // FIXME: we should set the surface that this saved buffer originates from |
@@ -348,8 +373,8 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, | |||
348 | if (state->border_left) { | 373 | if (state->border_left) { |
349 | memcpy(&color, colors->child_border, sizeof(float) * 4); | 374 | memcpy(&color, colors->child_border, sizeof(float) * 4); |
350 | premultiply_alpha(color, con->alpha); | 375 | premultiply_alpha(color, con->alpha); |
351 | box.x = state->x; | 376 | box.x = floor(state->x); |
352 | box.y = state->content_y; | 377 | box.y = floor(state->content_y); |
353 | box.width = state->border_thickness; | 378 | box.width = state->border_thickness; |
354 | box.height = state->content_height; | 379 | box.height = state->content_height; |
355 | scale_box(&box, output_scale); | 380 | scale_box(&box, output_scale); |
@@ -361,14 +386,14 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, | |||
361 | container_current_parent_layout(con); | 386 | container_current_parent_layout(con); |
362 | 387 | ||
363 | if (state->border_right) { | 388 | if (state->border_right) { |
364 | if (!container_is_floating(con) && siblings->length == 1 && layout == L_HORIZ) { | 389 | if (!container_is_current_floating(con) && siblings->length == 1 && layout == L_HORIZ) { |
365 | memcpy(&color, colors->indicator, sizeof(float) * 4); | 390 | memcpy(&color, colors->indicator, sizeof(float) * 4); |
366 | } else { | 391 | } else { |
367 | memcpy(&color, colors->child_border, sizeof(float) * 4); | 392 | memcpy(&color, colors->child_border, sizeof(float) * 4); |
368 | } | 393 | } |
369 | premultiply_alpha(color, con->alpha); | 394 | premultiply_alpha(color, con->alpha); |
370 | box.x = state->content_x + state->content_width; | 395 | box.x = floor(state->content_x + state->content_width); |
371 | box.y = state->content_y; | 396 | box.y = floor(state->content_y); |
372 | box.width = state->border_thickness; | 397 | box.width = state->border_thickness; |
373 | box.height = state->content_height; | 398 | box.height = state->content_height; |
374 | scale_box(&box, output_scale); | 399 | scale_box(&box, output_scale); |
@@ -376,14 +401,14 @@ static void render_view(struct sway_output *output, pixman_region32_t *damage, | |||
376 | } | 401 | } |
377 | 402 | ||
378 | if (state->border_bottom) { | 403 | if (state->border_bottom) { |
379 | if (!container_is_floating(con) && siblings->length == 1 && layout == L_VERT) { | 404 | if (!container_is_current_floating(con) && siblings->length == 1 && layout == L_VERT) { |
380 | memcpy(&color, colors->indicator, sizeof(float) * 4); | 405 | memcpy(&color, colors->indicator, sizeof(float) * 4); |
381 | } else { | 406 | } else { |
382 | memcpy(&color, colors->child_border, sizeof(float) * 4); | 407 | memcpy(&color, colors->child_border, sizeof(float) * 4); |
383 | } | 408 | } |
384 | premultiply_alpha(color, con->alpha); | 409 | premultiply_alpha(color, con->alpha); |
385 | box.x = state->x; | 410 | box.x = floor(state->x); |
386 | box.y = state->content_y + state->content_height; | 411 | box.y = floor(state->content_y + state->content_height); |
387 | box.width = state->width; | 412 | box.width = state->width; |
388 | box.height = state->border_thickness; | 413 | box.height = state->border_thickness; |
389 | scale_box(&box, output_scale); | 414 | scale_box(&box, output_scale); |
@@ -464,9 +489,10 @@ static void render_titlebar(struct sway_output *output, | |||
464 | int ob_marks_x = 0; // output-buffer-local | 489 | int ob_marks_x = 0; // output-buffer-local |
465 | int ob_marks_width = 0; // output-buffer-local | 490 | int ob_marks_width = 0; // output-buffer-local |
466 | if (config->show_marks && marks_texture) { | 491 | if (config->show_marks && marks_texture) { |
467 | struct wlr_box texture_box; | 492 | struct wlr_box texture_box = { |
468 | wlr_texture_get_size(marks_texture, | 493 | .width = marks_texture->width, |
469 | &texture_box.width, &texture_box.height); | 494 | .height = marks_texture->height, |
495 | }; | ||
470 | ob_marks_width = texture_box.width; | 496 | ob_marks_width = texture_box.width; |
471 | 497 | ||
472 | // The marks texture might be shorter than the config->font_height, in | 498 | // The marks texture might be shorter than the config->font_height, in |
@@ -517,15 +543,23 @@ static void render_titlebar(struct sway_output *output, | |||
517 | int ob_title_x = 0; // output-buffer-local | 543 | int ob_title_x = 0; // output-buffer-local |
518 | int ob_title_width = 0; // output-buffer-local | 544 | int ob_title_width = 0; // output-buffer-local |
519 | if (title_texture) { | 545 | if (title_texture) { |
520 | struct wlr_box texture_box; | 546 | struct wlr_box texture_box = { |
521 | wlr_texture_get_size(title_texture, | 547 | .width = title_texture->width, |
522 | &texture_box.width, &texture_box.height); | 548 | .height = title_texture->height, |
549 | }; | ||
550 | |||
551 | // The effective output may be NULL when con is not on any output. | ||
552 | // This can happen because we render all children of containers, | ||
553 | // even those that are out of the bounds of any output. | ||
554 | struct sway_output *effective = container_get_effective_output(con); | ||
555 | float title_scale = effective ? effective->wlr_output->scale : output_scale; | ||
556 | texture_box.width = texture_box.width * output_scale / title_scale; | ||
557 | texture_box.height = texture_box.height * output_scale / title_scale; | ||
523 | ob_title_width = texture_box.width; | 558 | ob_title_width = texture_box.width; |
524 | 559 | ||
525 | // The title texture might be shorter than the config->font_height, | 560 | // The title texture might be shorter than the config->font_height, |
526 | // in which case we need to pad it above and below. | 561 | // in which case we need to pad it above and below. |
527 | int ob_padding_above = round((config->font_baseline - | 562 | int ob_padding_above = round((titlebar_v_padding - |
528 | con->title_baseline + titlebar_v_padding - | ||
529 | titlebar_border_thickness) * output_scale); | 563 | titlebar_border_thickness) * output_scale); |
530 | int ob_padding_below = ob_bg_height - ob_padding_above - | 564 | int ob_padding_below = ob_bg_height - ob_padding_above - |
531 | texture_box.height; | 565 | texture_box.height; |
@@ -660,8 +694,8 @@ static void render_top_border(struct sway_output *output, | |||
660 | // Child border - top edge | 694 | // Child border - top edge |
661 | memcpy(&color, colors->child_border, sizeof(float) * 4); | 695 | memcpy(&color, colors->child_border, sizeof(float) * 4); |
662 | premultiply_alpha(color, con->alpha); | 696 | premultiply_alpha(color, con->alpha); |
663 | box.x = state->x; | 697 | box.x = floor(state->x); |
664 | box.y = state->y; | 698 | box.y = floor(state->y); |
665 | box.width = state->width; | 699 | box.width = state->width; |
666 | box.height = state->border_thickness; | 700 | box.height = state->border_thickness; |
667 | scale_box(&box, output_scale); | 701 | scale_box(&box, output_scale); |
@@ -716,8 +750,8 @@ static void render_containers_linear(struct sway_output *output, | |||
716 | } | 750 | } |
717 | 751 | ||
718 | if (state->border == B_NORMAL) { | 752 | if (state->border == B_NORMAL) { |
719 | render_titlebar(output, damage, child, state->x, | 753 | render_titlebar(output, damage, child, floor(state->x), |
720 | state->y, state->width, colors, | 754 | floor(state->y), state->width, colors, |
721 | title_texture, marks_texture); | 755 | title_texture, marks_texture); |
722 | } else if (state->border == B_PIXEL) { | 756 | } else if (state->border == B_PIXEL) { |
723 | render_top_border(output, damage, child, colors); | 757 | render_top_border(output, damage, child, colors); |
@@ -771,7 +805,7 @@ static void render_containers_tabbed(struct sway_output *output, | |||
771 | marks_texture = child->marks_unfocused; | 805 | marks_texture = child->marks_unfocused; |
772 | } | 806 | } |
773 | 807 | ||
774 | int x = cstate->x + tab_width * i; | 808 | int x = floor(cstate->x + tab_width * i); |
775 | 809 | ||
776 | // Make last tab use the remaining width of the parent | 810 | // Make last tab use the remaining width of the parent |
777 | if (i == parent->children->length - 1) { | 811 | if (i == parent->children->length - 1) { |
@@ -884,8 +918,8 @@ static void render_container(struct sway_output *output, | |||
884 | struct parent_data data = { | 918 | struct parent_data data = { |
885 | .layout = con->current.layout, | 919 | .layout = con->current.layout, |
886 | .box = { | 920 | .box = { |
887 | .x = con->current.x, | 921 | .x = floor(con->current.x), |
888 | .y = con->current.y, | 922 | .y = floor(con->current.y), |
889 | .width = con->current.width, | 923 | .width = con->current.width, |
890 | .height = con->current.height, | 924 | .height = con->current.height, |
891 | }, | 925 | }, |
@@ -901,8 +935,8 @@ static void render_workspace(struct sway_output *output, | |||
901 | struct parent_data data = { | 935 | struct parent_data data = { |
902 | .layout = ws->current.layout, | 936 | .layout = ws->current.layout, |
903 | .box = { | 937 | .box = { |
904 | .x = ws->current.x, | 938 | .x = floor(ws->current.x), |
905 | .y = ws->current.y, | 939 | .y = floor(ws->current.y), |
906 | .width = ws->current.width, | 940 | .width = ws->current.width, |
907 | .height = ws->current.height, | 941 | .height = ws->current.height, |
908 | }, | 942 | }, |
@@ -936,8 +970,8 @@ static void render_floating_container(struct sway_output *soutput, | |||
936 | } | 970 | } |
937 | 971 | ||
938 | if (con->current.border == B_NORMAL) { | 972 | if (con->current.border == B_NORMAL) { |
939 | render_titlebar(soutput, damage, con, con->current.x, | 973 | render_titlebar(soutput, damage, con, floor(con->current.x), |
940 | con->current.y, con->current.width, colors, | 974 | floor(con->current.y), con->current.width, colors, |
941 | title_texture, marks_texture); | 975 | title_texture, marks_texture); |
942 | } else if (con->current.border == B_PIXEL) { | 976 | } else if (con->current.border == B_PIXEL) { |
943 | render_top_border(soutput, damage, con, colors); | 977 | render_top_border(soutput, damage, con, colors); |
@@ -959,7 +993,7 @@ static void render_floating(struct sway_output *soutput, | |||
959 | } | 993 | } |
960 | for (int k = 0; k < ws->current.floating->length; ++k) { | 994 | for (int k = 0; k < ws->current.floating->length; ++k) { |
961 | struct sway_container *floater = ws->current.floating->items[k]; | 995 | struct sway_container *floater = ws->current.floating->items[k]; |
962 | if (floater->fullscreen_mode != FULLSCREEN_NONE) { | 996 | if (floater->current.fullscreen_mode != FULLSCREEN_NONE) { |
963 | continue; | 997 | continue; |
964 | } | 998 | } |
965 | render_floating_container(soutput, damage, floater); | 999 | render_floating_container(soutput, damage, floater); |
@@ -999,6 +1033,12 @@ void output_render(struct sway_output *output, struct timespec *when, | |||
999 | 1033 | ||
1000 | wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); | 1034 | wlr_renderer_begin(renderer, wlr_output->width, wlr_output->height); |
1001 | 1035 | ||
1036 | if (debug.damage == DAMAGE_RERENDER) { | ||
1037 | int width, height; | ||
1038 | wlr_output_transformed_resolution(wlr_output, &width, &height); | ||
1039 | pixman_region32_union_rect(damage, damage, 0, 0, width, height); | ||
1040 | } | ||
1041 | |||
1002 | if (!pixman_region32_not_empty(damage)) { | 1042 | if (!pixman_region32_not_empty(damage)) { |
1003 | // Output isn't damaged but needs buffer swap | 1043 | // Output isn't damaged but needs buffer swap |
1004 | goto renderer_end; | 1044 | goto renderer_end; |
@@ -1006,10 +1046,6 @@ void output_render(struct sway_output *output, struct timespec *when, | |||
1006 | 1046 | ||
1007 | if (debug.damage == DAMAGE_HIGHLIGHT) { | 1047 | if (debug.damage == DAMAGE_HIGHLIGHT) { |
1008 | wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); | 1048 | wlr_renderer_clear(renderer, (float[]){1, 1, 0, 1}); |
1009 | } else if (debug.damage == DAMAGE_RERENDER) { | ||
1010 | int width, height; | ||
1011 | wlr_output_transformed_resolution(wlr_output, &width, &height); | ||
1012 | pixman_region32_union_rect(damage, damage, 0, 0, width, height); | ||
1013 | } | 1049 | } |
1014 | 1050 | ||
1015 | if (output_has_opaque_overlay_layer_surface(output)) { | 1051 | if (output_has_opaque_overlay_layer_surface(output)) { |
@@ -1110,7 +1146,7 @@ renderer_end: | |||
1110 | wlr_region_transform(&frame_damage, &output->damage->current, | 1146 | wlr_region_transform(&frame_damage, &output->damage->current, |
1111 | transform, width, height); | 1147 | transform, width, height); |
1112 | 1148 | ||
1113 | if (debug.damage == DAMAGE_HIGHLIGHT) { | 1149 | if (debug.damage != DAMAGE_DEFAULT) { |
1114 | pixman_region32_union_rect(&frame_damage, &frame_damage, | 1150 | pixman_region32_union_rect(&frame_damage, &frame_damage, |
1115 | 0, 0, wlr_output->width, wlr_output->height); | 1151 | 0, 0, wlr_output->width, wlr_output->height); |
1116 | } | 1152 | } |
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c index eac38991..b1f3fb32 100644 --- a/sway/desktop/transaction.c +++ b/sway/desktop/transaction.c | |||
@@ -35,6 +35,8 @@ struct sway_transaction_instruction { | |||
35 | struct sway_container_state container_state; | 35 | struct sway_container_state container_state; |
36 | }; | 36 | }; |
37 | uint32_t serial; | 37 | uint32_t serial; |
38 | bool server_request; | ||
39 | bool waiting; | ||
38 | }; | 40 | }; |
39 | 41 | ||
40 | static struct sway_transaction *transaction_create(void) { | 42 | static struct sway_transaction *transaction_create(void) { |
@@ -86,7 +88,11 @@ static void transaction_destroy(struct sway_transaction *transaction) { | |||
86 | static void copy_output_state(struct sway_output *output, | 88 | static void copy_output_state(struct sway_output *output, |
87 | struct sway_transaction_instruction *instruction) { | 89 | struct sway_transaction_instruction *instruction) { |
88 | struct sway_output_state *state = &instruction->output_state; | 90 | struct sway_output_state *state = &instruction->output_state; |
89 | state->workspaces = create_list(); | 91 | if (state->workspaces) { |
92 | state->workspaces->length = 0; | ||
93 | } else { | ||
94 | state->workspaces = create_list(); | ||
95 | } | ||
90 | list_cat(state->workspaces, output->workspaces); | 96 | list_cat(state->workspaces, output->workspaces); |
91 | 97 | ||
92 | state->active_workspace = output_get_active_workspace(output); | 98 | state->active_workspace = output_get_active_workspace(output); |
@@ -104,8 +110,16 @@ static void copy_workspace_state(struct sway_workspace *ws, | |||
104 | state->layout = ws->layout; | 110 | state->layout = ws->layout; |
105 | 111 | ||
106 | state->output = ws->output; | 112 | state->output = ws->output; |
107 | state->floating = create_list(); | 113 | if (state->floating) { |
108 | state->tiling = create_list(); | 114 | state->floating->length = 0; |
115 | } else { | ||
116 | state->floating = create_list(); | ||
117 | } | ||
118 | if (state->tiling) { | ||
119 | state->tiling->length = 0; | ||
120 | } else { | ||
121 | state->tiling = create_list(); | ||
122 | } | ||
109 | list_cat(state->floating, ws->floating); | 123 | list_cat(state->floating, ws->floating); |
110 | list_cat(state->tiling, ws->tiling); | 124 | list_cat(state->tiling, ws->tiling); |
111 | 125 | ||
@@ -115,8 +129,8 @@ static void copy_workspace_state(struct sway_workspace *ws, | |||
115 | // Set focused_inactive_child to the direct tiling child | 129 | // Set focused_inactive_child to the direct tiling child |
116 | struct sway_container *focus = seat_get_focus_inactive_tiling(seat, ws); | 130 | struct sway_container *focus = seat_get_focus_inactive_tiling(seat, ws); |
117 | if (focus) { | 131 | if (focus) { |
118 | while (focus->parent) { | 132 | while (focus->pending.parent) { |
119 | focus = focus->parent; | 133 | focus = focus->pending.parent; |
120 | } | 134 | } |
121 | } | 135 | } |
122 | state->focused_inactive_child = focus; | 136 | state->focused_inactive_child = focus; |
@@ -126,28 +140,19 @@ static void copy_container_state(struct sway_container *container, | |||
126 | struct sway_transaction_instruction *instruction) { | 140 | struct sway_transaction_instruction *instruction) { |
127 | struct sway_container_state *state = &instruction->container_state; | 141 | struct sway_container_state *state = &instruction->container_state; |
128 | 142 | ||
129 | state->layout = container->layout; | 143 | if (state->children) { |
130 | state->x = container->x; | 144 | list_free(state->children); |
131 | state->y = container->y; | 145 | } |
132 | state->width = container->width; | 146 | |
133 | state->height = container->height; | 147 | memcpy(state, &container->pending, sizeof(struct sway_container_state)); |
134 | state->fullscreen_mode = container->fullscreen_mode; | ||
135 | state->parent = container->parent; | ||
136 | state->workspace = container->workspace; | ||
137 | state->border = container->border; | ||
138 | state->border_thickness = container->border_thickness; | ||
139 | state->border_top = container->border_top; | ||
140 | state->border_left = container->border_left; | ||
141 | state->border_right = container->border_right; | ||
142 | state->border_bottom = container->border_bottom; | ||
143 | state->content_x = container->content_x; | ||
144 | state->content_y = container->content_y; | ||
145 | state->content_width = container->content_width; | ||
146 | state->content_height = container->content_height; | ||
147 | 148 | ||
148 | if (!container->view) { | 149 | if (!container->view) { |
150 | // We store a copy of the child list to avoid having it mutated after | ||
151 | // we copy the state. | ||
149 | state->children = create_list(); | 152 | state->children = create_list(); |
150 | list_cat(state->children, container->children); | 153 | list_cat(state->children, container->pending.children); |
154 | } else { | ||
155 | state->children = NULL; | ||
151 | } | 156 | } |
152 | 157 | ||
153 | struct sway_seat *seat = input_manager_current_seat(); | 158 | struct sway_seat *seat = input_manager_current_seat(); |
@@ -161,14 +166,36 @@ static void copy_container_state(struct sway_container *container, | |||
161 | } | 166 | } |
162 | 167 | ||
163 | static void transaction_add_node(struct sway_transaction *transaction, | 168 | static void transaction_add_node(struct sway_transaction *transaction, |
164 | struct sway_node *node) { | 169 | struct sway_node *node, bool server_request) { |
165 | struct sway_transaction_instruction *instruction = | 170 | struct sway_transaction_instruction *instruction = NULL; |
166 | calloc(1, sizeof(struct sway_transaction_instruction)); | 171 | |
167 | if (!sway_assert(instruction, "Unable to allocate instruction")) { | 172 | // Check if we have an instruction for this node already, in which case we |
168 | return; | 173 | // update that instead of creating a new one. |
174 | if (node->ntxnrefs > 0) { | ||
175 | for (int idx = 0; idx < transaction->instructions->length; idx++) { | ||
176 | struct sway_transaction_instruction *other = | ||
177 | transaction->instructions->items[idx]; | ||
178 | if (other->node == node) { | ||
179 | instruction = other; | ||
180 | break; | ||
181 | } | ||
182 | } | ||
183 | } | ||
184 | |||
185 | if (!instruction) { | ||
186 | instruction = calloc(1, sizeof(struct sway_transaction_instruction)); | ||
187 | if (!sway_assert(instruction, "Unable to allocate instruction")) { | ||
188 | return; | ||
189 | } | ||
190 | instruction->transaction = transaction; | ||
191 | instruction->node = node; | ||
192 | instruction->server_request = server_request; | ||
193 | |||
194 | list_add(transaction->instructions, instruction); | ||
195 | node->ntxnrefs++; | ||
196 | } else if (server_request) { | ||
197 | instruction->server_request = true; | ||
169 | } | 198 | } |
170 | instruction->transaction = transaction; | ||
171 | instruction->node = node; | ||
172 | 199 | ||
173 | switch (node->type) { | 200 | switch (node->type) { |
174 | case N_ROOT: | 201 | case N_ROOT: |
@@ -183,9 +210,6 @@ static void transaction_add_node(struct sway_transaction *transaction, | |||
183 | copy_container_state(node->sway_container, instruction); | 210 | copy_container_state(node->sway_container, instruction); |
184 | break; | 211 | break; |
185 | } | 212 | } |
186 | |||
187 | list_add(transaction->instructions, instruction); | ||
188 | node->ntxnrefs++; | ||
189 | } | 213 | } |
190 | 214 | ||
191 | static void apply_output_state(struct sway_output *output, | 215 | static void apply_output_state(struct sway_output *output, |
@@ -214,8 +238,8 @@ static void apply_container_state(struct sway_container *container, | |||
214 | struct sway_saved_buffer *saved_buf; | 238 | struct sway_saved_buffer *saved_buf; |
215 | wl_list_for_each(saved_buf, &view->saved_buffers, link) { | 239 | wl_list_for_each(saved_buf, &view->saved_buffers, link) { |
216 | struct wlr_box box = { | 240 | struct wlr_box box = { |
217 | .x = container->current.content_x - view->saved_geometry.x + saved_buf->x, | 241 | .x = saved_buf->x - view->saved_geometry.x, |
218 | .y = container->current.content_y - view->saved_geometry.y + saved_buf->y, | 242 | .y = saved_buf->y - view->saved_geometry.y, |
219 | .width = saved_buf->width, | 243 | .width = saved_buf->width, |
220 | .height = saved_buf->height, | 244 | .height = saved_buf->height, |
221 | }; | 245 | }; |
@@ -238,6 +262,13 @@ static void apply_container_state(struct sway_container *container, | |||
238 | } | 262 | } |
239 | } | 263 | } |
240 | 264 | ||
265 | // If the view hasn't responded to the configure, center it within | ||
266 | // the container. This is important for fullscreen views which | ||
267 | // refuse to resize to the size of the output. | ||
268 | if (view && view->surface) { | ||
269 | view_center_surface(view); | ||
270 | } | ||
271 | |||
241 | // Damage the new location | 272 | // Damage the new location |
242 | desktop_damage_whole_container(container); | 273 | desktop_damage_whole_container(container); |
243 | if (view && view->surface) { | 274 | if (view && view->surface) { |
@@ -251,24 +282,6 @@ static void apply_container_state(struct sway_container *container, | |||
251 | desktop_damage_box(&box); | 282 | desktop_damage_box(&box); |
252 | } | 283 | } |
253 | 284 | ||
254 | // If the view hasn't responded to the configure, center it within | ||
255 | // the container. This is important for fullscreen views which | ||
256 | // refuse to resize to the size of the output. | ||
257 | if (view && view->surface) { | ||
258 | if (view->geometry.width < container->current.content_width) { | ||
259 | container->surface_x = container->current.content_x + | ||
260 | (container->current.content_width - view->geometry.width) / 2; | ||
261 | } else { | ||
262 | container->surface_x = container->current.content_x; | ||
263 | } | ||
264 | if (view->geometry.height < container->current.content_height) { | ||
265 | container->surface_y = container->current.content_y + | ||
266 | (container->current.content_height - view->geometry.height) / 2; | ||
267 | } else { | ||
268 | container->surface_y = container->current.content_y; | ||
269 | } | ||
270 | } | ||
271 | |||
272 | if (!container->node.destroying) { | 285 | if (!container->node.destroying) { |
273 | container_discover_outputs(container); | 286 | container_discover_outputs(container); |
274 | } | 287 | } |
@@ -317,70 +330,25 @@ static void transaction_apply(struct sway_transaction *transaction) { | |||
317 | cursor_rebase_all(); | 330 | cursor_rebase_all(); |
318 | } | 331 | } |
319 | 332 | ||
320 | static void transaction_commit(struct sway_transaction *transaction); | 333 | static void transaction_commit_pending(void); |
321 | 334 | ||
322 | // Return true if both transactions operate on the same nodes | 335 | static void transaction_progress(void) { |
323 | static bool transaction_same_nodes(struct sway_transaction *a, | 336 | if (!server.queued_transaction) { |
324 | struct sway_transaction *b) { | ||
325 | if (a->instructions->length != b->instructions->length) { | ||
326 | return false; | ||
327 | } | ||
328 | for (int i = 0; i < a->instructions->length; ++i) { | ||
329 | struct sway_transaction_instruction *a_inst = a->instructions->items[i]; | ||
330 | struct sway_transaction_instruction *b_inst = b->instructions->items[i]; | ||
331 | if (a_inst->node != b_inst->node) { | ||
332 | return false; | ||
333 | } | ||
334 | } | ||
335 | return true; | ||
336 | } | ||
337 | |||
338 | static void transaction_progress_queue(void) { | ||
339 | if (!server.transactions->length) { | ||
340 | return; | 337 | return; |
341 | } | 338 | } |
342 | // Only the first transaction in the queue is committed, so that's the one | 339 | if (server.queued_transaction->num_waiting > 0) { |
343 | // we try to process. | ||
344 | struct sway_transaction *transaction = server.transactions->items[0]; | ||
345 | if (transaction->num_waiting) { | ||
346 | return; | 340 | return; |
347 | } | 341 | } |
348 | transaction_apply(transaction); | 342 | transaction_apply(server.queued_transaction); |
349 | transaction_destroy(transaction); | 343 | transaction_destroy(server.queued_transaction); |
350 | list_del(server.transactions, 0); | 344 | server.queued_transaction = NULL; |
351 | 345 | ||
352 | if (server.transactions->length == 0) { | 346 | if (!server.pending_transaction) { |
353 | // The transaction queue is empty, so we're done. | ||
354 | sway_idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); | 347 | sway_idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1); |
355 | return; | 348 | return; |
356 | } | 349 | } |
357 | 350 | ||
358 | // If there's a bunch of consecutive transactions which all apply to the | 351 | transaction_commit_pending(); |
359 | // same views, skip all except the last one. | ||
360 | while (server.transactions->length >= 2) { | ||
361 | struct sway_transaction *txn = server.transactions->items[0]; | ||
362 | struct sway_transaction *dup = NULL; | ||
363 | |||
364 | for (int i = 1; i < server.transactions->length; i++) { | ||
365 | struct sway_transaction *maybe_dup = server.transactions->items[i]; | ||
366 | if (transaction_same_nodes(txn, maybe_dup)) { | ||
367 | dup = maybe_dup; | ||
368 | break; | ||
369 | } | ||
370 | } | ||
371 | |||
372 | if (dup) { | ||
373 | list_del(server.transactions, 0); | ||
374 | transaction_destroy(txn); | ||
375 | } else { | ||
376 | break; | ||
377 | } | ||
378 | } | ||
379 | |||
380 | // We again commit the first transaction in the queue to process it. | ||
381 | transaction = server.transactions->items[0]; | ||
382 | transaction_commit(transaction); | ||
383 | transaction_progress_queue(); | ||
384 | } | 352 | } |
385 | 353 | ||
386 | static int handle_timeout(void *data) { | 354 | static int handle_timeout(void *data) { |
@@ -388,7 +356,7 @@ static int handle_timeout(void *data) { | |||
388 | sway_log(SWAY_DEBUG, "Transaction %p timed out (%zi waiting)", | 356 | sway_log(SWAY_DEBUG, "Transaction %p timed out (%zi waiting)", |
389 | transaction, transaction->num_waiting); | 357 | transaction, transaction->num_waiting); |
390 | transaction->num_waiting = 0; | 358 | transaction->num_waiting = 0; |
391 | transaction_progress_queue(); | 359 | transaction_progress(); |
392 | return 0; | 360 | return 0; |
393 | } | 361 | } |
394 | 362 | ||
@@ -400,6 +368,9 @@ static bool should_configure(struct sway_node *node, | |||
400 | if (node->destroying) { | 368 | if (node->destroying) { |
401 | return false; | 369 | return false; |
402 | } | 370 | } |
371 | if (!instruction->server_request) { | ||
372 | return false; | ||
373 | } | ||
403 | struct sway_container_state *cstate = &node->sway_container->current; | 374 | struct sway_container_state *cstate = &node->sway_container->current; |
404 | struct sway_container_state *istate = &instruction->container_state; | 375 | struct sway_container_state *istate = &instruction->container_state; |
405 | #if HAVE_XWAYLAND | 376 | #if HAVE_XWAYLAND |
@@ -431,13 +402,18 @@ static void transaction_commit(struct sway_transaction *transaction) { | |||
431 | struct sway_transaction_instruction *instruction = | 402 | struct sway_transaction_instruction *instruction = |
432 | transaction->instructions->items[i]; | 403 | transaction->instructions->items[i]; |
433 | struct sway_node *node = instruction->node; | 404 | struct sway_node *node = instruction->node; |
405 | bool hidden = node_is_view(node) && | ||
406 | !view_is_visible(node->sway_container->view); | ||
434 | if (should_configure(node, instruction)) { | 407 | if (should_configure(node, instruction)) { |
435 | instruction->serial = view_configure(node->sway_container->view, | 408 | instruction->serial = view_configure(node->sway_container->view, |
436 | instruction->container_state.content_x, | 409 | instruction->container_state.content_x, |
437 | instruction->container_state.content_y, | 410 | instruction->container_state.content_y, |
438 | instruction->container_state.content_width, | 411 | instruction->container_state.content_width, |
439 | instruction->container_state.content_height); | 412 | instruction->container_state.content_height); |
440 | ++transaction->num_waiting; | 413 | if (!hidden) { |
414 | instruction->waiting = true; | ||
415 | ++transaction->num_waiting; | ||
416 | } | ||
441 | 417 | ||
442 | // From here on we are rendering a saved buffer of the view, which | 418 | // From here on we are rendering a saved buffer of the view, which |
443 | // means we can send a frame done event to make the client redraw it | 419 | // means we can send a frame done event to make the client redraw it |
@@ -448,7 +424,8 @@ static void transaction_commit(struct sway_transaction *transaction) { | |||
448 | wlr_surface_send_frame_done( | 424 | wlr_surface_send_frame_done( |
449 | node->sway_container->view->surface, &now); | 425 | node->sway_container->view->surface, &now); |
450 | } | 426 | } |
451 | if (node_is_view(node) && wl_list_empty(&node->sway_container->view->saved_buffers)) { | 427 | if (!hidden && node_is_view(node) && |
428 | wl_list_empty(&node->sway_container->view->saved_buffers)) { | ||
452 | view_save_buffer(node->sway_container->view); | 429 | view_save_buffer(node->sway_container->view); |
453 | memcpy(&node->sway_container->view->saved_geometry, | 430 | memcpy(&node->sway_container->view->saved_geometry, |
454 | &node->sway_container->view->geometry, | 431 | &node->sway_container->view->geometry, |
@@ -483,6 +460,17 @@ static void transaction_commit(struct sway_transaction *transaction) { | |||
483 | } | 460 | } |
484 | } | 461 | } |
485 | 462 | ||
463 | static void transaction_commit_pending(void) { | ||
464 | if (server.queued_transaction) { | ||
465 | return; | ||
466 | } | ||
467 | struct sway_transaction *transaction = server.pending_transaction; | ||
468 | server.pending_transaction = NULL; | ||
469 | server.queued_transaction = transaction; | ||
470 | transaction_commit(transaction); | ||
471 | transaction_progress(); | ||
472 | } | ||
473 | |||
486 | static void set_instruction_ready( | 474 | static void set_instruction_ready( |
487 | struct sway_transaction_instruction *instruction) { | 475 | struct sway_transaction_instruction *instruction) { |
488 | struct sway_transaction *transaction = instruction->transaction; | 476 | struct sway_transaction *transaction = instruction->transaction; |
@@ -501,13 +489,14 @@ static void set_instruction_ready( | |||
501 | } | 489 | } |
502 | 490 | ||
503 | // If the transaction has timed out then its num_waiting will be 0 already. | 491 | // If the transaction has timed out then its num_waiting will be 0 already. |
504 | if (transaction->num_waiting > 0 && --transaction->num_waiting == 0) { | 492 | if (instruction->waiting && transaction->num_waiting > 0 && |
493 | --transaction->num_waiting == 0) { | ||
505 | sway_log(SWAY_DEBUG, "Transaction %p is ready", transaction); | 494 | sway_log(SWAY_DEBUG, "Transaction %p is ready", transaction); |
506 | wl_event_source_timer_update(transaction->timer, 0); | 495 | wl_event_source_timer_update(transaction->timer, 0); |
507 | } | 496 | } |
508 | 497 | ||
509 | instruction->node->instruction = NULL; | 498 | instruction->node->instruction = NULL; |
510 | transaction_progress_queue(); | 499 | transaction_progress(); |
511 | } | 500 | } |
512 | 501 | ||
513 | void transaction_notify_view_ready_by_serial(struct sway_view *view, | 502 | void transaction_notify_view_ready_by_serial(struct sway_view *view, |
@@ -532,36 +521,32 @@ void transaction_notify_view_ready_by_geometry(struct sway_view *view, | |||
532 | } | 521 | } |
533 | } | 522 | } |
534 | 523 | ||
535 | void transaction_notify_view_ready_immediately(struct sway_view *view) { | 524 | static void _transaction_commit_dirty(bool server_request) { |
536 | struct sway_transaction_instruction *instruction = | ||
537 | view->container->node.instruction; | ||
538 | if (instruction != NULL) { | ||
539 | set_instruction_ready(instruction); | ||
540 | } | ||
541 | } | ||
542 | |||
543 | void transaction_commit_dirty(void) { | ||
544 | if (!server.dirty_nodes->length) { | 525 | if (!server.dirty_nodes->length) { |
545 | return; | 526 | return; |
546 | } | 527 | } |
547 | struct sway_transaction *transaction = transaction_create(); | 528 | |
548 | if (!transaction) { | 529 | if (!server.pending_transaction) { |
549 | return; | 530 | server.pending_transaction = transaction_create(); |
531 | if (!server.pending_transaction) { | ||
532 | return; | ||
533 | } | ||
550 | } | 534 | } |
535 | |||
551 | for (int i = 0; i < server.dirty_nodes->length; ++i) { | 536 | for (int i = 0; i < server.dirty_nodes->length; ++i) { |
552 | struct sway_node *node = server.dirty_nodes->items[i]; | 537 | struct sway_node *node = server.dirty_nodes->items[i]; |
553 | transaction_add_node(transaction, node); | 538 | transaction_add_node(server.pending_transaction, node, server_request); |
554 | node->dirty = false; | 539 | node->dirty = false; |
555 | } | 540 | } |
556 | server.dirty_nodes->length = 0; | 541 | server.dirty_nodes->length = 0; |
557 | 542 | ||
558 | list_add(server.transactions, transaction); | 543 | transaction_commit_pending(); |
544 | } | ||
559 | 545 | ||
560 | // We only commit the first transaction added to the queue. | 546 | void transaction_commit_dirty(void) { |
561 | if (server.transactions->length == 1) { | 547 | _transaction_commit_dirty(true); |
562 | transaction_commit(transaction); | 548 | } |
563 | // Attempting to progress the queue here is useful | 549 | |
564 | // if the transaction has nothing to wait for. | 550 | void transaction_commit_dirty_client(void) { |
565 | transaction_progress_queue(); | 551 | _transaction_commit_dirty(false); |
566 | } | ||
567 | } | 552 | } |
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c index 667fb9e5..c1e5bc68 100644 --- a/sway/desktop/xdg_shell.c +++ b/sway/desktop/xdg_shell.c | |||
@@ -21,18 +21,15 @@ | |||
21 | 21 | ||
22 | static const struct sway_view_child_impl popup_impl; | 22 | static const struct sway_view_child_impl popup_impl; |
23 | 23 | ||
24 | static void popup_get_root_coords(struct sway_view_child *child, | 24 | static void popup_get_view_coords(struct sway_view_child *child, |
25 | int *root_sx, int *root_sy) { | 25 | int *sx, int *sy) { |
26 | struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child; | 26 | struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child; |
27 | struct wlr_xdg_surface *surface = popup->wlr_xdg_surface; | 27 | struct wlr_xdg_surface *surface = popup->wlr_xdg_surface; |
28 | 28 | ||
29 | int x_offset = -child->view->geometry.x - surface->geometry.x; | ||
30 | int y_offset = -child->view->geometry.y - surface->geometry.y; | ||
31 | |||
32 | wlr_xdg_popup_get_toplevel_coords(surface->popup, | 29 | wlr_xdg_popup_get_toplevel_coords(surface->popup, |
33 | x_offset + surface->popup->geometry.x, | 30 | surface->popup->geometry.x - surface->current.geometry.x, |
34 | y_offset + surface->popup->geometry.y, | 31 | surface->popup->geometry.y - surface->current.geometry.y, |
35 | root_sx, root_sy); | 32 | sx, sy); |
36 | } | 33 | } |
37 | 34 | ||
38 | static void popup_destroy(struct sway_view_child *child) { | 35 | static void popup_destroy(struct sway_view_child *child) { |
@@ -47,7 +44,7 @@ static void popup_destroy(struct sway_view_child *child) { | |||
47 | } | 44 | } |
48 | 45 | ||
49 | static const struct sway_view_child_impl popup_impl = { | 46 | static const struct sway_view_child_impl popup_impl = { |
50 | .get_root_coords = popup_get_root_coords, | 47 | .get_view_coords = popup_get_view_coords, |
51 | .destroy = popup_destroy, | 48 | .destroy = popup_destroy, |
52 | }; | 49 | }; |
53 | 50 | ||
@@ -70,13 +67,13 @@ static void popup_unconstrain(struct sway_xdg_popup *popup) { | |||
70 | struct sway_view *view = popup->child.view; | 67 | struct sway_view *view = popup->child.view; |
71 | struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_surface->popup; | 68 | struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_surface->popup; |
72 | 69 | ||
73 | struct sway_output *output = view->container->workspace->output; | 70 | struct sway_output *output = view->container->pending.workspace->output; |
74 | 71 | ||
75 | // the output box expressed in the coordinate system of the toplevel parent | 72 | // the output box expressed in the coordinate system of the toplevel parent |
76 | // of the popup | 73 | // of the popup |
77 | struct wlr_box output_toplevel_sx_box = { | 74 | struct wlr_box output_toplevel_sx_box = { |
78 | .x = output->lx - view->container->content_x, | 75 | .x = output->lx - view->container->pending.content_x, |
79 | .y = output->ly - view->container->content_y, | 76 | .y = output->ly - view->container->pending.content_y, |
80 | .width = output->width, | 77 | .width = output->width, |
81 | .height = output->height, | 78 | .height = output->height, |
82 | }; | 79 | }; |
@@ -293,19 +290,23 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
293 | new_geo.y != view->geometry.y; | 290 | new_geo.y != view->geometry.y; |
294 | 291 | ||
295 | if (new_size) { | 292 | if (new_size) { |
296 | // The view has unexpectedly sent a new size | 293 | // The client changed its surface size in this commit. For floating |
294 | // containers, we resize the container to match. For tiling containers, | ||
295 | // we only recenter the surface. | ||
297 | desktop_damage_view(view); | 296 | desktop_damage_view(view); |
298 | view_update_size(view, new_geo.width, new_geo.height); | ||
299 | memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); | 297 | memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); |
298 | if (container_is_floating(view->container)) { | ||
299 | view_update_size(view); | ||
300 | transaction_commit_dirty_client(); | ||
301 | } else { | ||
302 | view_center_surface(view); | ||
303 | } | ||
300 | desktop_damage_view(view); | 304 | desktop_damage_view(view); |
301 | transaction_commit_dirty(); | ||
302 | } | 305 | } |
303 | 306 | ||
304 | if (view->container->node.instruction) { | 307 | if (view->container->node.instruction) { |
305 | transaction_notify_view_ready_by_serial(view, | 308 | transaction_notify_view_ready_by_serial(view, |
306 | xdg_surface->configure_serial); | 309 | xdg_surface->current.configure_serial); |
307 | } else if (new_size) { | ||
308 | transaction_notify_view_ready_immediately(view); | ||
309 | } | 310 | } |
310 | 311 | ||
311 | view_damage_from(view); | 312 | view_damage_from(view); |
@@ -354,7 +355,8 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) | |||
354 | if (e->fullscreen && e->output && e->output->data) { | 355 | if (e->fullscreen && e->output && e->output->data) { |
355 | struct sway_output *output = e->output->data; | 356 | struct sway_output *output = e->output->data; |
356 | struct sway_workspace *ws = output_get_active_workspace(output); | 357 | struct sway_workspace *ws = output_get_active_workspace(output); |
357 | if (ws && !container_is_scratchpad_hidden(container)) { | 358 | if (ws && !container_is_scratchpad_hidden(container) && |
359 | container->pending.workspace != ws) { | ||
358 | if (container_is_floating(container)) { | 360 | if (container_is_floating(container)) { |
359 | workspace_add_floating(ws, container); | 361 | workspace_add_floating(ws, container); |
360 | } else { | 362 | } else { |
@@ -369,11 +371,6 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data) | |||
369 | transaction_commit_dirty(); | 371 | transaction_commit_dirty(); |
370 | } | 372 | } |
371 | 373 | ||
372 | static void handle_request_maximize(struct wl_listener *listener, void *data) { | ||
373 | struct wlr_xdg_surface *surface = data; | ||
374 | wlr_xdg_surface_schedule_configure(surface); | ||
375 | } | ||
376 | |||
377 | static void handle_request_move(struct wl_listener *listener, void *data) { | 374 | static void handle_request_move(struct wl_listener *listener, void *data) { |
378 | struct sway_xdg_shell_view *xdg_shell_view = | 375 | struct sway_xdg_shell_view *xdg_shell_view = |
379 | wl_container_of(listener, xdg_shell_view, request_move); | 376 | wl_container_of(listener, xdg_shell_view, request_move); |
@@ -416,7 +413,6 @@ static void handle_unmap(struct wl_listener *listener, void *data) { | |||
416 | wl_list_remove(&xdg_shell_view->commit.link); | 413 | wl_list_remove(&xdg_shell_view->commit.link); |
417 | wl_list_remove(&xdg_shell_view->new_popup.link); | 414 | wl_list_remove(&xdg_shell_view->new_popup.link); |
418 | wl_list_remove(&xdg_shell_view->request_fullscreen.link); | 415 | wl_list_remove(&xdg_shell_view->request_fullscreen.link); |
419 | wl_list_remove(&xdg_shell_view->request_maximize.link); | ||
420 | wl_list_remove(&xdg_shell_view->request_move.link); | 416 | wl_list_remove(&xdg_shell_view->request_move.link); |
421 | wl_list_remove(&xdg_shell_view->request_resize.link); | 417 | wl_list_remove(&xdg_shell_view->request_resize.link); |
422 | wl_list_remove(&xdg_shell_view->set_title.link); | 418 | wl_list_remove(&xdg_shell_view->set_title.link); |
@@ -429,8 +425,8 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
429 | struct sway_view *view = &xdg_shell_view->view; | 425 | struct sway_view *view = &xdg_shell_view->view; |
430 | struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface; | 426 | struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_surface; |
431 | 427 | ||
432 | view->natural_width = view->wlr_xdg_surface->geometry.width; | 428 | view->natural_width = view->wlr_xdg_surface->current.geometry.width; |
433 | view->natural_height = view->wlr_xdg_surface->geometry.height; | 429 | view->natural_height = view->wlr_xdg_surface->current.geometry.height; |
434 | if (!view->natural_width && !view->natural_height) { | 430 | if (!view->natural_width && !view->natural_height) { |
435 | view->natural_width = view->wlr_xdg_surface->surface->current.width; | 431 | view->natural_width = view->wlr_xdg_surface->surface->current.width; |
436 | view->natural_height = view->wlr_xdg_surface->surface->current.height; | 432 | view->natural_height = view->wlr_xdg_surface->surface->current.height; |
@@ -438,17 +434,20 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
438 | 434 | ||
439 | bool csd = false; | 435 | bool csd = false; |
440 | 436 | ||
441 | if (!view->xdg_decoration) { | 437 | if (view->xdg_decoration) { |
438 | enum wlr_xdg_toplevel_decoration_v1_mode mode = | ||
439 | view->xdg_decoration->wlr_xdg_decoration->requested_mode; | ||
440 | csd = mode == WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; | ||
441 | } else { | ||
442 | struct sway_server_decoration *deco = | 442 | struct sway_server_decoration *deco = |
443 | decoration_from_surface(xdg_surface->surface); | 443 | decoration_from_surface(xdg_surface->surface); |
444 | csd = !deco || deco->wlr_server_decoration->mode == | 444 | csd = !deco || deco->wlr_server_decoration->mode == |
445 | WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT; | 445 | WLR_SERVER_DECORATION_MANAGER_MODE_CLIENT; |
446 | |||
447 | } | 446 | } |
448 | 447 | ||
449 | view_map(view, view->wlr_xdg_surface->surface, | 448 | view_map(view, view->wlr_xdg_surface->surface, |
450 | xdg_surface->toplevel->client_pending.fullscreen, | 449 | xdg_surface->toplevel->requested.fullscreen, |
451 | xdg_surface->toplevel->client_pending.fullscreen_output, | 450 | xdg_surface->toplevel->requested.fullscreen_output, |
452 | csd); | 451 | csd); |
453 | 452 | ||
454 | transaction_commit_dirty(); | 453 | transaction_commit_dirty(); |
@@ -465,10 +464,6 @@ static void handle_map(struct wl_listener *listener, void *data) { | |||
465 | wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, | 464 | wl_signal_add(&xdg_surface->toplevel->events.request_fullscreen, |
466 | &xdg_shell_view->request_fullscreen); | 465 | &xdg_shell_view->request_fullscreen); |
467 | 466 | ||
468 | xdg_shell_view->request_maximize.notify = handle_request_maximize; | ||
469 | wl_signal_add(&xdg_surface->toplevel->events.request_maximize, | ||
470 | &xdg_shell_view->request_maximize); | ||
471 | |||
472 | xdg_shell_view->request_move.notify = handle_request_move; | 467 | xdg_shell_view->request_move.notify = handle_request_move; |
473 | wl_signal_add(&xdg_surface->toplevel->events.request_move, | 468 | wl_signal_add(&xdg_surface->toplevel->events.request_move, |
474 | &xdg_shell_view->request_move); | 469 | &xdg_shell_view->request_move); |
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c index e1a2e463..1af8d248 100644 --- a/sway/desktop/xwayland.c +++ b/sway/desktop/xwayland.c | |||
@@ -105,14 +105,10 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) { | |||
105 | if (seat->wlr_seat->keyboard_state.focused_surface == xsurface->surface) { | 105 | if (seat->wlr_seat->keyboard_state.focused_surface == xsurface->surface) { |
106 | // This simply returns focus to the parent surface if there's one available. | 106 | // This simply returns focus to the parent surface if there's one available. |
107 | // This seems to handle JetBrains issues. | 107 | // This seems to handle JetBrains issues. |
108 | if (xsurface->parent && xsurface->parent->surface && | 108 | if (xsurface->parent && xsurface->parent->surface |
109 | wlr_surface_is_xwayland_surface(xsurface->parent->surface)) { | 109 | && wlr_xwayland_or_surface_wants_focus(xsurface->parent)) { |
110 | struct wlr_xwayland_surface *next_surface = | 110 | seat_set_focus_surface(seat, xsurface->parent->surface, false); |
111 | wlr_xwayland_surface_from_wlr_surface(xsurface->parent->surface); | 111 | return; |
112 | if (wlr_xwayland_or_surface_wants_focus(next_surface)) { | ||
113 | seat_set_focus_surface(seat, xsurface->parent->surface, false); | ||
114 | return; | ||
115 | } | ||
116 | } | 112 | } |
117 | 113 | ||
118 | // Restore focus | 114 | // Restore focus |
@@ -258,6 +254,7 @@ static void set_activated(struct sway_view *view, bool activated) { | |||
258 | } | 254 | } |
259 | 255 | ||
260 | wlr_xwayland_surface_activate(surface, activated); | 256 | wlr_xwayland_surface_activate(surface, activated); |
257 | wlr_xwayland_surface_restack(surface, NULL, XCB_STACK_MODE_ABOVE); | ||
261 | } | 258 | } |
262 | 259 | ||
263 | static void set_tiled(struct sway_view *view, bool tiled) { | 260 | static void set_tiled(struct sway_view *view, bool tiled) { |
@@ -399,30 +396,31 @@ static void handle_commit(struct wl_listener *listener, void *data) { | |||
399 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; | 396 | struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface; |
400 | struct wlr_surface_state *state = &xsurface->surface->current; | 397 | struct wlr_surface_state *state = &xsurface->surface->current; |
401 | 398 | ||
399 | struct wlr_box new_geo; | ||
400 | get_geometry(view, &new_geo); | ||
401 | bool new_size = new_geo.width != view->geometry.width || | ||
402 | new_geo.height != view->geometry.height || | ||
403 | new_geo.x != view->geometry.x || | ||
404 | new_geo.y != view->geometry.y; | ||
405 | |||
406 | if (new_size) { | ||
407 | // The client changed its surface size in this commit. For floating | ||
408 | // containers, we resize the container to match. For tiling containers, | ||
409 | // we only recenter the surface. | ||
410 | desktop_damage_view(view); | ||
411 | memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); | ||
412 | if (container_is_floating(view->container)) { | ||
413 | view_update_size(view); | ||
414 | transaction_commit_dirty_client(); | ||
415 | } else { | ||
416 | view_center_surface(view); | ||
417 | } | ||
418 | desktop_damage_view(view); | ||
419 | } | ||
420 | |||
402 | if (view->container->node.instruction) { | 421 | if (view->container->node.instruction) { |
403 | get_geometry(view, &view->geometry); | ||
404 | transaction_notify_view_ready_by_geometry(view, | 422 | transaction_notify_view_ready_by_geometry(view, |
405 | xsurface->x, xsurface->y, state->width, state->height); | 423 | xsurface->x, xsurface->y, state->width, state->height); |
406 | } else { | ||
407 | struct wlr_box new_geo; | ||
408 | get_geometry(view, &new_geo); | ||
409 | |||
410 | if ((new_geo.width != view->geometry.width || | ||
411 | new_geo.height != view->geometry.height || | ||
412 | new_geo.x != view->geometry.x || | ||
413 | new_geo.y != view->geometry.y)) { | ||
414 | // The view has unexpectedly sent a new size | ||
415 | // eg. The Firefox "Save As" dialog when downloading a file | ||
416 | desktop_damage_view(view); | ||
417 | view_update_size(view, new_geo.width, new_geo.height); | ||
418 | memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); | ||
419 | desktop_damage_view(view); | ||
420 | transaction_commit_dirty(); | ||
421 | transaction_notify_view_ready_by_geometry(view, | ||
422 | xsurface->x, xsurface->y, new_geo.width, new_geo.height); | ||
423 | } else { | ||
424 | memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box)); | ||
425 | } | ||
426 | } | 424 | } |
427 | 425 | ||
428 | view_damage_from(view); | 426 | view_damage_from(view); |
@@ -527,10 +525,10 @@ static void handle_request_configure(struct wl_listener *listener, void *data) { | |||
527 | view->natural_height = ev->height; | 525 | view->natural_height = ev->height; |
528 | container_floating_resize_and_center(view->container); | 526 | container_floating_resize_and_center(view->container); |
529 | 527 | ||
530 | configure(view, view->container->content_x, | 528 | configure(view, view->container->pending.content_x, |
531 | view->container->content_y, | 529 | view->container->pending.content_y, |
532 | view->container->content_width, | 530 | view->container->pending.content_width, |
533 | view->container->content_height); | 531 | view->container->pending.content_height); |
534 | node_set_dirty(&view->container->node); | 532 | node_set_dirty(&view->container->node); |
535 | } else { | 533 | } else { |
536 | configure(view, view->container->current.content_x, | 534 | configure(view, view->container->current.content_x, |
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index fa604426..1e3e16d6 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -4,8 +4,8 @@ | |||
4 | #include <libevdev/libevdev.h> | 4 | #include <libevdev/libevdev.h> |
5 | #include <linux/input-event-codes.h> | 5 | #include <linux/input-event-codes.h> |
6 | #include <errno.h> | 6 | #include <errno.h> |
7 | #include <time.h> | ||
7 | #include <strings.h> | 8 | #include <strings.h> |
8 | #include <wlr/types/wlr_box.h> | ||
9 | #include <wlr/types/wlr_cursor.h> | 9 | #include <wlr/types/wlr_cursor.h> |
10 | #include <wlr/types/wlr_idle.h> | 10 | #include <wlr/types/wlr_idle.h> |
11 | #include <wlr/types/wlr_pointer.h> | 11 | #include <wlr/types/wlr_pointer.h> |
@@ -20,7 +20,6 @@ | |||
20 | #include "util.h" | 20 | #include "util.h" |
21 | #include "sway/commands.h" | 21 | #include "sway/commands.h" |
22 | #include "sway/desktop.h" | 22 | #include "sway/desktop.h" |
23 | #include "sway/desktop/transaction.h" | ||
24 | #include "sway/input/cursor.h" | 23 | #include "sway/input/cursor.h" |
25 | #include "sway/input/keyboard.h" | 24 | #include "sway/input/keyboard.h" |
26 | #include "sway/input/tablet.h" | 25 | #include "sway/input/tablet.h" |
@@ -32,6 +31,12 @@ | |||
32 | #include "sway/tree/workspace.h" | 31 | #include "sway/tree/workspace.h" |
33 | #include "wlr-layer-shell-unstable-v1-protocol.h" | 32 | #include "wlr-layer-shell-unstable-v1-protocol.h" |
34 | 33 | ||
34 | static uint32_t get_current_time_msec(void) { | ||
35 | struct timespec now; | ||
36 | clock_gettime(CLOCK_MONOTONIC, &now); | ||
37 | return now.tv_sec * 1000 + now.tv_nsec / 1000000; | ||
38 | } | ||
39 | |||
35 | static struct wlr_surface *layer_surface_at(struct sway_output *output, | 40 | static struct wlr_surface *layer_surface_at(struct sway_output *output, |
36 | struct wl_list *layer, double ox, double oy, double *sx, double *sy) { | 41 | struct wl_list *layer, double ox, double oy, double *sx, double *sy) { |
37 | struct sway_layer_surface *sway_layer; | 42 | struct sway_layer_surface *sway_layer; |
@@ -383,7 +388,6 @@ static void handle_pointer_motion_relative( | |||
383 | 388 | ||
384 | pointer_motion(cursor, e->time_msec, e->device, e->delta_x, e->delta_y, | 389 | pointer_motion(cursor, e->time_msec, e->device, e->delta_x, e->delta_y, |
385 | e->unaccel_dx, e->unaccel_dy); | 390 | e->unaccel_dx, e->unaccel_dy); |
386 | transaction_commit_dirty(); | ||
387 | } | 391 | } |
388 | 392 | ||
389 | static void handle_pointer_motion_absolute( | 393 | static void handle_pointer_motion_absolute( |
@@ -401,7 +405,6 @@ static void handle_pointer_motion_absolute( | |||
401 | double dy = ly - cursor->cursor->y; | 405 | double dy = ly - cursor->cursor->y; |
402 | 406 | ||
403 | pointer_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy); | 407 | pointer_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy); |
404 | transaction_commit_dirty(); | ||
405 | } | 408 | } |
406 | 409 | ||
407 | void dispatch_cursor_button(struct sway_cursor *cursor, | 410 | void dispatch_cursor_button(struct sway_cursor *cursor, |
@@ -431,7 +434,6 @@ static void handle_pointer_button(struct wl_listener *listener, void *data) { | |||
431 | cursor_handle_activity_from_device(cursor, event->device); | 434 | cursor_handle_activity_from_device(cursor, event->device); |
432 | dispatch_cursor_button(cursor, event->device, | 435 | dispatch_cursor_button(cursor, event->device, |
433 | event->time_msec, event->button, event->state); | 436 | event->time_msec, event->button, event->state); |
434 | transaction_commit_dirty(); | ||
435 | } | 437 | } |
436 | 438 | ||
437 | void dispatch_cursor_axis(struct sway_cursor *cursor, | 439 | void dispatch_cursor_axis(struct sway_cursor *cursor, |
@@ -444,7 +446,6 @@ static void handle_pointer_axis(struct wl_listener *listener, void *data) { | |||
444 | struct wlr_event_pointer_axis *event = data; | 446 | struct wlr_event_pointer_axis *event = data; |
445 | cursor_handle_activity_from_device(cursor, event->device); | 447 | cursor_handle_activity_from_device(cursor, event->device); |
446 | dispatch_cursor_axis(cursor, event); | 448 | dispatch_cursor_axis(cursor, event); |
447 | transaction_commit_dirty(); | ||
448 | } | 449 | } |
449 | 450 | ||
450 | static void handle_pointer_frame(struct wl_listener *listener, void *data) { | 451 | static void handle_pointer_frame(struct wl_listener *listener, void *data) { |
@@ -494,8 +495,6 @@ static void handle_touch_down(struct wl_listener *listener, void *data) { | |||
494 | pointer_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy); | 495 | pointer_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy); |
495 | dispatch_cursor_button(cursor, event->device, event->time_msec, | 496 | dispatch_cursor_button(cursor, event->device, event->time_msec, |
496 | BTN_LEFT, WLR_BUTTON_PRESSED); | 497 | BTN_LEFT, WLR_BUTTON_PRESSED); |
497 | wlr_seat_pointer_notify_frame(wlr_seat); | ||
498 | transaction_commit_dirty(); | ||
499 | } | 498 | } |
500 | } | 499 | } |
501 | 500 | ||
@@ -508,11 +507,9 @@ static void handle_touch_up(struct wl_listener *listener, void *data) { | |||
508 | 507 | ||
509 | if (cursor->simulating_pointer_from_touch) { | 508 | if (cursor->simulating_pointer_from_touch) { |
510 | if (cursor->pointer_touch_id == cursor->seat->touch_id) { | 509 | if (cursor->pointer_touch_id == cursor->seat->touch_id) { |
511 | cursor->simulating_pointer_from_touch = false; | 510 | cursor->pointer_touch_up = true; |
512 | dispatch_cursor_button(cursor, event->device, event->time_msec, | 511 | dispatch_cursor_button(cursor, event->device, event->time_msec, |
513 | BTN_LEFT, WLR_BUTTON_RELEASED); | 512 | BTN_LEFT, WLR_BUTTON_RELEASED); |
514 | wlr_seat_pointer_notify_frame(wlr_seat); | ||
515 | transaction_commit_dirty(); | ||
516 | } | 513 | } |
517 | } else { | 514 | } else { |
518 | wlr_seat_touch_notify_up(wlr_seat, event->time_msec, event->touch_id); | 515 | wlr_seat_touch_notify_up(wlr_seat, event->time_msec, event->touch_id); |
@@ -553,7 +550,6 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) { | |||
553 | dx = lx - cursor->cursor->x; | 550 | dx = lx - cursor->cursor->x; |
554 | dy = ly - cursor->cursor->y; | 551 | dy = ly - cursor->cursor->y; |
555 | pointer_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy); | 552 | pointer_motion(cursor, event->time_msec, event->device, dx, dy, dx, dy); |
556 | transaction_commit_dirty(); | ||
557 | } | 553 | } |
558 | } else if (surface) { | 554 | } else if (surface) { |
559 | wlr_seat_touch_notify_motion(wlr_seat, event->time_msec, | 555 | wlr_seat_touch_notify_motion(wlr_seat, event->time_msec, |
@@ -561,6 +557,24 @@ static void handle_touch_motion(struct wl_listener *listener, void *data) { | |||
561 | } | 557 | } |
562 | } | 558 | } |
563 | 559 | ||
560 | static void handle_touch_frame(struct wl_listener *listener, void *data) { | ||
561 | struct sway_cursor *cursor = | ||
562 | wl_container_of(listener, cursor, touch_frame); | ||
563 | |||
564 | struct wlr_seat *wlr_seat = cursor->seat->wlr_seat; | ||
565 | |||
566 | if (cursor->simulating_pointer_from_touch) { | ||
567 | wlr_seat_pointer_notify_frame(wlr_seat); | ||
568 | |||
569 | if (cursor->pointer_touch_up) { | ||
570 | cursor->pointer_touch_up = false; | ||
571 | cursor->simulating_pointer_from_touch = false; | ||
572 | } | ||
573 | } else { | ||
574 | wlr_seat_touch_notify_frame(wlr_seat); | ||
575 | } | ||
576 | } | ||
577 | |||
564 | static double apply_mapping_from_coord(double low, double high, double value) { | 578 | static double apply_mapping_from_coord(double low, double high, double value) { |
565 | if (isnan(value)) { | 579 | if (isnan(value)) { |
566 | return value; | 580 | return value; |
@@ -639,8 +653,6 @@ static void handle_tablet_tool_position(struct sway_cursor *cursor, | |||
639 | wlr_tablet_v2_tablet_tool_notify_proximity_out(tool->tablet_v2_tool); | 653 | wlr_tablet_v2_tablet_tool_notify_proximity_out(tool->tablet_v2_tool); |
640 | pointer_motion(cursor, time_msec, input_device->wlr_device, dx, dy, dx, dy); | 654 | pointer_motion(cursor, time_msec, input_device->wlr_device, dx, dy, dx, dy); |
641 | } | 655 | } |
642 | |||
643 | transaction_commit_dirty(); | ||
644 | } | 656 | } |
645 | 657 | ||
646 | static void handle_tool_axis(struct wl_listener *listener, void *data) { | 658 | static void handle_tool_axis(struct wl_listener *listener, void *data) { |
@@ -720,7 +732,6 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) { | |||
720 | dispatch_cursor_button(cursor, event->device, event->time_msec, | 732 | dispatch_cursor_button(cursor, event->device, event->time_msec, |
721 | BTN_LEFT, WLR_BUTTON_RELEASED); | 733 | BTN_LEFT, WLR_BUTTON_RELEASED); |
722 | wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); | 734 | wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); |
723 | transaction_commit_dirty(); | ||
724 | } else if (!surface || !wlr_surface_accepts_tablet_v2(tablet_v2, surface)) { | 735 | } else if (!surface || !wlr_surface_accepts_tablet_v2(tablet_v2, surface)) { |
725 | // If we started holding the tool tip down on a surface that accepts | 736 | // If we started holding the tool tip down on a surface that accepts |
726 | // tablet v2, we should notify that surface if it gets released over a | 737 | // tablet v2, we should notify that surface if it gets released over a |
@@ -733,7 +744,6 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) { | |||
733 | dispatch_cursor_button(cursor, event->device, event->time_msec, | 744 | dispatch_cursor_button(cursor, event->device, event->time_msec, |
734 | BTN_LEFT, WLR_BUTTON_PRESSED); | 745 | BTN_LEFT, WLR_BUTTON_PRESSED); |
735 | wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); | 746 | wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); |
736 | transaction_commit_dirty(); | ||
737 | } | 747 | } |
738 | } else { | 748 | } else { |
739 | seatop_tablet_tool_tip(seat, sway_tool, event->time_msec, event->state); | 749 | seatop_tablet_tool_tip(seat, sway_tool, event->time_msec, event->state); |
@@ -820,7 +830,6 @@ static void handle_tool_button(struct wl_listener *listener, void *data) { | |||
820 | break; | 830 | break; |
821 | } | 831 | } |
822 | wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); | 832 | wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat); |
823 | transaction_commit_dirty(); | ||
824 | return; | 833 | return; |
825 | } | 834 | } |
826 | 835 | ||
@@ -837,8 +846,8 @@ static void check_constraint_region(struct sway_cursor *cursor) { | |||
837 | 846 | ||
838 | struct sway_container *con = view->container; | 847 | struct sway_container *con = view->container; |
839 | 848 | ||
840 | double sx = cursor->cursor->x - con->content_x + view->geometry.x; | 849 | double sx = cursor->cursor->x - con->pending.content_x + view->geometry.x; |
841 | double sy = cursor->cursor->y - con->content_y + view->geometry.y; | 850 | double sy = cursor->cursor->y - con->pending.content_y + view->geometry.y; |
842 | 851 | ||
843 | if (!pixman_region32_contains_point(region, | 852 | if (!pixman_region32_contains_point(region, |
844 | floor(sx), floor(sy), NULL)) { | 853 | floor(sx), floor(sy), NULL)) { |
@@ -849,8 +858,8 @@ static void check_constraint_region(struct sway_cursor *cursor) { | |||
849 | double sy = (boxes[0].y1 + boxes[0].y2) / 2.; | 858 | double sy = (boxes[0].y1 + boxes[0].y2) / 2.; |
850 | 859 | ||
851 | wlr_cursor_warp_closest(cursor->cursor, NULL, | 860 | wlr_cursor_warp_closest(cursor->cursor, NULL, |
852 | sx + con->content_x - view->geometry.x, | 861 | sx + con->pending.content_x - view->geometry.x, |
853 | sy + con->content_y - view->geometry.y); | 862 | sy + con->pending.content_y - view->geometry.y); |
854 | 863 | ||
855 | cursor_rebase(cursor); | 864 | cursor_rebase(cursor); |
856 | } | 865 | } |
@@ -1051,6 +1060,7 @@ void sway_cursor_destroy(struct sway_cursor *cursor) { | |||
1051 | wl_list_remove(&cursor->touch_down.link); | 1060 | wl_list_remove(&cursor->touch_down.link); |
1052 | wl_list_remove(&cursor->touch_up.link); | 1061 | wl_list_remove(&cursor->touch_up.link); |
1053 | wl_list_remove(&cursor->touch_motion.link); | 1062 | wl_list_remove(&cursor->touch_motion.link); |
1063 | wl_list_remove(&cursor->touch_frame.link); | ||
1054 | wl_list_remove(&cursor->tool_axis.link); | 1064 | wl_list_remove(&cursor->tool_axis.link); |
1055 | wl_list_remove(&cursor->tool_tip.link); | 1065 | wl_list_remove(&cursor->tool_tip.link); |
1056 | wl_list_remove(&cursor->tool_button.link); | 1066 | wl_list_remove(&cursor->tool_button.link); |
@@ -1126,6 +1136,9 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) { | |||
1126 | &cursor->touch_motion); | 1136 | &cursor->touch_motion); |
1127 | cursor->touch_motion.notify = handle_touch_motion; | 1137 | cursor->touch_motion.notify = handle_touch_motion; |
1128 | 1138 | ||
1139 | wl_signal_add(&wlr_cursor->events.touch_frame, &cursor->touch_frame); | ||
1140 | cursor->touch_frame.notify = handle_touch_frame; | ||
1141 | |||
1129 | wl_signal_add(&wlr_cursor->events.tablet_tool_axis, | 1142 | wl_signal_add(&wlr_cursor->events.tablet_tool_axis, |
1130 | &cursor->tool_axis); | 1143 | &cursor->tool_axis); |
1131 | cursor->tool_axis.notify = handle_tool_axis; | 1144 | cursor->tool_axis.notify = handle_tool_axis; |
@@ -1170,8 +1183,8 @@ void cursor_warp_to_container(struct sway_cursor *cursor, | |||
1170 | return; | 1183 | return; |
1171 | } | 1184 | } |
1172 | 1185 | ||
1173 | double x = container->x + container->width / 2.0; | 1186 | double x = container->pending.x + container->pending.width / 2.0; |
1174 | double y = container->y + container->height / 2.0; | 1187 | double y = container->pending.y + container->pending.height / 2.0; |
1175 | 1188 | ||
1176 | wlr_cursor_warp(cursor->cursor, NULL, x, y); | 1189 | wlr_cursor_warp(cursor->cursor, NULL, x, y); |
1177 | cursor_unhide(cursor); | 1190 | cursor_unhide(cursor); |
@@ -1284,8 +1297,8 @@ static void warp_to_constraint_cursor_hint(struct sway_cursor *cursor) { | |||
1284 | struct sway_view *view = view_from_wlr_surface(constraint->surface); | 1297 | struct sway_view *view = view_from_wlr_surface(constraint->surface); |
1285 | struct sway_container *con = view->container; | 1298 | struct sway_container *con = view->container; |
1286 | 1299 | ||
1287 | double lx = sx + con->content_x - view->geometry.x; | 1300 | double lx = sx + con->pending.content_x - view->geometry.x; |
1288 | double ly = sy + con->content_y - view->geometry.y; | 1301 | double ly = sy + con->pending.content_y - view->geometry.y; |
1289 | 1302 | ||
1290 | wlr_cursor_warp(cursor->cursor, NULL, lx, ly); | 1303 | wlr_cursor_warp(cursor->cursor, NULL, lx, ly); |
1291 | 1304 | ||
@@ -1333,7 +1346,7 @@ void handle_pointer_constraint(struct wl_listener *listener, void *data) { | |||
1333 | wl_signal_add(&constraint->events.destroy, &sway_constraint->destroy); | 1346 | wl_signal_add(&constraint->events.destroy, &sway_constraint->destroy); |
1334 | 1347 | ||
1335 | struct sway_node *focus = seat_get_focus(seat); | 1348 | struct sway_node *focus = seat_get_focus(seat); |
1336 | if (focus && focus->type == N_CONTAINER && focus->sway_container->view) { | 1349 | if (focus && node_is_view(focus)) { |
1337 | struct wlr_surface *surface = focus->sway_container->view->surface; | 1350 | struct wlr_surface *surface = focus->sway_container->view->surface; |
1338 | if (surface == constraint->surface) { | 1351 | if (surface == constraint->surface) { |
1339 | sway_cursor_constrain(seat->cursor, constraint); | 1352 | sway_cursor_constrain(seat->cursor, constraint); |
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index ce259eb2..f258ac7d 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c | |||
@@ -9,7 +9,6 @@ | |||
9 | #include <wlr/types/wlr_keyboard_group.h> | 9 | #include <wlr/types/wlr_keyboard_group.h> |
10 | #include <xkbcommon/xkbcommon-names.h> | 10 | #include <xkbcommon/xkbcommon-names.h> |
11 | #include "sway/commands.h" | 11 | #include "sway/commands.h" |
12 | #include "sway/desktop/transaction.h" | ||
13 | #include "sway/input/input-manager.h" | 12 | #include "sway/input/input-manager.h" |
14 | #include "sway/input/keyboard.h" | 13 | #include "sway/input/keyboard.h" |
15 | #include "sway/input/seat.h" | 14 | #include "sway/input/seat.h" |
@@ -379,6 +378,28 @@ static void update_keyboard_state(struct sway_keyboard *keyboard, | |||
379 | } | 378 | } |
380 | } | 379 | } |
381 | 380 | ||
381 | /** | ||
382 | * Get keyboard grab of the seat from sway_keyboard if we should forward events | ||
383 | * to it. | ||
384 | * | ||
385 | * Returns NULL if the keyboard is not grabbed by an input method, | ||
386 | * or if event is from virtual keyboard of the same client as grab. | ||
387 | * TODO: see swaywm/wlroots#2322 | ||
388 | */ | ||
389 | static struct wlr_input_method_keyboard_grab_v2 *keyboard_get_im_grab( | ||
390 | struct sway_keyboard *keyboard) { | ||
391 | struct wlr_input_method_v2 *input_method = keyboard->seat_device-> | ||
392 | sway_seat->im_relay.input_method; | ||
393 | struct wlr_virtual_keyboard_v1 *virtual_keyboard = | ||
394 | wlr_input_device_get_virtual_keyboard(keyboard->seat_device->input_device->wlr_device); | ||
395 | if (!input_method || !input_method->keyboard_grab || (virtual_keyboard && | ||
396 | wl_resource_get_client(virtual_keyboard->resource) == | ||
397 | wl_resource_get_client(input_method->keyboard_grab->resource))) { | ||
398 | return NULL; | ||
399 | } | ||
400 | return input_method->keyboard_grab; | ||
401 | } | ||
402 | |||
382 | static void handle_key_event(struct sway_keyboard *keyboard, | 403 | static void handle_key_event(struct sway_keyboard *keyboard, |
383 | struct wlr_event_keyboard_key *event) { | 404 | struct wlr_event_keyboard_key *event) { |
384 | struct sway_seat *seat = keyboard->seat_device->sway_seat; | 405 | struct sway_seat *seat = keyboard->seat_device->sway_seat; |
@@ -489,18 +510,42 @@ static void handle_key_event(struct sway_keyboard *keyboard, | |||
489 | keyinfo.raw_keysyms_len); | 510 | keyinfo.raw_keysyms_len); |
490 | } | 511 | } |
491 | 512 | ||
492 | if (!handled || event->state == WL_KEYBOARD_KEY_STATE_RELEASED) { | 513 | if (event->state == WL_KEYBOARD_KEY_STATE_RELEASED) { |
514 | // If the pressed event was sent to a client, also send the released | ||
515 | // event. In particular, don't send the released event to the IM grab. | ||
493 | bool pressed_sent = update_shortcut_state( | 516 | bool pressed_sent = update_shortcut_state( |
494 | &keyboard->state_pressed_sent, event->keycode, event->state, | 517 | &keyboard->state_pressed_sent, event->keycode, |
495 | keyinfo.keycode, 0); | 518 | event->state, keyinfo.keycode, 0); |
496 | if (pressed_sent || event->state == WL_KEYBOARD_KEY_STATE_PRESSED) { | 519 | if (pressed_sent) { |
497 | wlr_seat_set_keyboard(wlr_seat, wlr_device); | 520 | wlr_seat_set_keyboard(wlr_seat, wlr_device); |
498 | wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, | 521 | wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, |
499 | event->keycode, event->state); | 522 | event->keycode, event->state); |
523 | handled = true; | ||
524 | } | ||
525 | } | ||
526 | |||
527 | if (!handled) { | ||
528 | struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(keyboard); | ||
529 | |||
530 | if (kb_grab) { | ||
531 | wlr_input_method_keyboard_grab_v2_set_keyboard(kb_grab, | ||
532 | wlr_device->keyboard); | ||
533 | wlr_input_method_keyboard_grab_v2_send_key(kb_grab, | ||
534 | event->time_msec, event->keycode, event->state); | ||
535 | handled = true; | ||
500 | } | 536 | } |
501 | } | 537 | } |
502 | 538 | ||
503 | transaction_commit_dirty(); | 539 | if (!handled && event->state != WL_KEYBOARD_KEY_STATE_RELEASED) { |
540 | // If a released event failed pressed sent test, and not in sent to | ||
541 | // keyboard grab, it is still not handled. Don't handle released here. | ||
542 | update_shortcut_state( | ||
543 | &keyboard->state_pressed_sent, event->keycode, event->state, | ||
544 | keyinfo.keycode, 0); | ||
545 | wlr_seat_set_keyboard(wlr_seat, wlr_device); | ||
546 | wlr_seat_keyboard_notify_key(wlr_seat, event->time_msec, | ||
547 | event->keycode, event->state); | ||
548 | } | ||
504 | 549 | ||
505 | free(device_identifier); | 550 | free(device_identifier); |
506 | } | 551 | } |
@@ -587,7 +632,6 @@ static int handle_keyboard_repeat(void *data) { | |||
587 | 632 | ||
588 | seat_execute_command(keyboard->seat_device->sway_seat, | 633 | seat_execute_command(keyboard->seat_device->sway_seat, |
589 | keyboard->repeat_binding); | 634 | keyboard->repeat_binding); |
590 | transaction_commit_dirty(); | ||
591 | } | 635 | } |
592 | return 0; | 636 | return 0; |
593 | } | 637 | } |
@@ -617,10 +661,19 @@ static void handle_modifier_event(struct sway_keyboard *keyboard) { | |||
617 | struct wlr_input_device *wlr_device = | 661 | struct wlr_input_device *wlr_device = |
618 | keyboard->seat_device->input_device->wlr_device; | 662 | keyboard->seat_device->input_device->wlr_device; |
619 | if (!wlr_device->keyboard->group) { | 663 | if (!wlr_device->keyboard->group) { |
620 | struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat; | 664 | struct wlr_input_method_keyboard_grab_v2 *kb_grab = keyboard_get_im_grab(keyboard); |
621 | wlr_seat_set_keyboard(wlr_seat, wlr_device); | 665 | |
622 | wlr_seat_keyboard_notify_modifiers(wlr_seat, | 666 | if (kb_grab) { |
623 | &wlr_device->keyboard->modifiers); | 667 | wlr_input_method_keyboard_grab_v2_set_keyboard(kb_grab, |
668 | wlr_device->keyboard); | ||
669 | wlr_input_method_keyboard_grab_v2_send_modifiers(kb_grab, | ||
670 | &wlr_device->keyboard->modifiers); | ||
671 | } else { | ||
672 | struct wlr_seat *wlr_seat = keyboard->seat_device->sway_seat->wlr_seat; | ||
673 | wlr_seat_set_keyboard(wlr_seat, wlr_device); | ||
674 | wlr_seat_keyboard_notify_modifiers(wlr_seat, | ||
675 | &wlr_device->keyboard->modifiers); | ||
676 | } | ||
624 | 677 | ||
625 | uint32_t modifiers = wlr_keyboard_get_modifiers(wlr_device->keyboard); | 678 | uint32_t modifiers = wlr_keyboard_get_modifiers(wlr_device->keyboard); |
626 | determine_bar_visibility(modifiers); | 679 | determine_bar_visibility(modifiers); |
diff --git a/sway/input/libinput.c b/sway/input/libinput.c index 54520f9e..3c0f359d 100644 --- a/sway/input/libinput.c +++ b/sway/input/libinput.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #include <float.h> | 1 | #include <float.h> |
2 | #include <libinput.h> | 2 | #include <libinput.h> |
3 | #include <libudev.h> | ||
3 | #include <limits.h> | 4 | #include <limits.h> |
4 | #include <wlr/backend/libinput.h> | 5 | #include <wlr/backend/libinput.h> |
5 | #include "log.h" | 6 | #include "log.h" |
@@ -312,3 +313,32 @@ void sway_input_reset_libinput_device(struct sway_input_device *input_device) { | |||
312 | ipc_event_input("libinput_config", input_device); | 313 | ipc_event_input("libinput_config", input_device); |
313 | } | 314 | } |
314 | } | 315 | } |
316 | |||
317 | bool sway_libinput_device_is_builtin(struct sway_input_device *sway_device) { | ||
318 | if (!wlr_input_device_is_libinput(sway_device->wlr_device)) { | ||
319 | return false; | ||
320 | } | ||
321 | |||
322 | struct libinput_device *device = | ||
323 | wlr_libinput_get_device_handle(sway_device->wlr_device); | ||
324 | struct udev_device *udev_device = | ||
325 | libinput_device_get_udev_device(device); | ||
326 | if (!udev_device) { | ||
327 | return false; | ||
328 | } | ||
329 | |||
330 | const char *id_path = udev_device_get_property_value(udev_device, "ID_PATH"); | ||
331 | if (!id_path) { | ||
332 | return false; | ||
333 | } | ||
334 | |||
335 | const char prefix_platform[] = "platform-"; | ||
336 | if (strncmp(id_path, prefix_platform, strlen(prefix_platform)) != 0) { | ||
337 | return false; | ||
338 | } | ||
339 | |||
340 | const char prefix_pci[] = "pci-"; | ||
341 | const char infix_platform[] = "-platform-"; | ||
342 | return (strncmp(id_path, prefix_pci, strlen(prefix_pci)) == 0) && | ||
343 | strstr(id_path, infix_platform); | ||
344 | } | ||
diff --git a/sway/input/seat.c b/sway/input/seat.c index 1f5865ee..c5c8459e 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include "sway/input/cursor.h" | 20 | #include "sway/input/cursor.h" |
21 | #include "sway/input/input-manager.h" | 21 | #include "sway/input/input-manager.h" |
22 | #include "sway/input/keyboard.h" | 22 | #include "sway/input/keyboard.h" |
23 | #include "sway/input/libinput.h" | ||
23 | #include "sway/input/seat.h" | 24 | #include "sway/input/seat.h" |
24 | #include "sway/input/switch.h" | 25 | #include "sway/input/switch.h" |
25 | #include "sway/input/tablet.h" | 26 | #include "sway/input/tablet.h" |
@@ -209,14 +210,13 @@ void seat_for_each_node(struct sway_seat *seat, | |||
209 | 210 | ||
210 | struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat, | 211 | struct sway_container *seat_get_focus_inactive_view(struct sway_seat *seat, |
211 | struct sway_node *ancestor) { | 212 | struct sway_node *ancestor) { |
212 | if (ancestor->type == N_CONTAINER && ancestor->sway_container->view) { | 213 | if (node_is_view(ancestor)) { |
213 | return ancestor->sway_container; | 214 | return ancestor->sway_container; |
214 | } | 215 | } |
215 | struct sway_seat_node *current; | 216 | struct sway_seat_node *current; |
216 | wl_list_for_each(current, &seat->focus_stack, link) { | 217 | wl_list_for_each(current, &seat->focus_stack, link) { |
217 | struct sway_node *node = current->node; | 218 | struct sway_node *node = current->node; |
218 | if (node->type == N_CONTAINER && node->sway_container->view && | 219 | if (node_is_view(node) && node_has_ancestor(node, ancestor)) { |
219 | node_has_ancestor(node, ancestor)) { | ||
220 | return node->sway_container; | 220 | return node->sway_container; |
221 | } | 221 | } |
222 | } | 222 | } |
@@ -309,8 +309,8 @@ static void handle_seat_node_destroy(struct wl_listener *listener, void *data) { | |||
309 | // Setting focus_inactive | 309 | // Setting focus_inactive |
310 | focus = seat_get_focus_inactive(seat, &root->node); | 310 | focus = seat_get_focus_inactive(seat, &root->node); |
311 | seat_set_raw_focus(seat, next_focus); | 311 | seat_set_raw_focus(seat, next_focus); |
312 | if (focus->type == N_CONTAINER && focus->sway_container->workspace) { | 312 | if (focus->type == N_CONTAINER && focus->sway_container->pending.workspace) { |
313 | seat_set_raw_focus(seat, &focus->sway_container->workspace->node); | 313 | seat_set_raw_focus(seat, &focus->sway_container->pending.workspace->node); |
314 | } | 314 | } |
315 | seat_set_raw_focus(seat, focus); | 315 | seat_set_raw_focus(seat, focus); |
316 | } | 316 | } |
@@ -666,6 +666,40 @@ static void seat_reset_input_config(struct sway_seat *seat, | |||
666 | sway_device->input_device->wlr_device, NULL); | 666 | sway_device->input_device->wlr_device, NULL); |
667 | } | 667 | } |
668 | 668 | ||
669 | static bool has_prefix(const char *str, const char *prefix) { | ||
670 | return strncmp(str, prefix, strlen(prefix)) == 0; | ||
671 | } | ||
672 | |||
673 | /** | ||
674 | * Get the name of the built-in output, if any. Returns NULL if there isn't | ||
675 | * exactly one built-in output. | ||
676 | */ | ||
677 | static const char *get_builtin_output_name(void) { | ||
678 | const char *match = NULL; | ||
679 | for (int i = 0; i < root->outputs->length; ++i) { | ||
680 | struct sway_output *output = root->outputs->items[i]; | ||
681 | const char *name = output->wlr_output->name; | ||
682 | if (has_prefix(name, "eDP-") || has_prefix(name, "LVDS-") || | ||
683 | has_prefix(name, "DSI-")) { | ||
684 | if (match != NULL) { | ||
685 | return NULL; | ||
686 | } | ||
687 | match = name; | ||
688 | } | ||
689 | } | ||
690 | return match; | ||
691 | } | ||
692 | |||
693 | static bool is_touch_or_tablet_tool(struct sway_seat_device *seat_device) { | ||
694 | switch (seat_device->input_device->wlr_device->type) { | ||
695 | case WLR_INPUT_DEVICE_TOUCH: | ||
696 | case WLR_INPUT_DEVICE_TABLET_TOOL: | ||
697 | return true; | ||
698 | default: | ||
699 | return false; | ||
700 | } | ||
701 | } | ||
702 | |||
669 | static void seat_apply_input_config(struct sway_seat *seat, | 703 | static void seat_apply_input_config(struct sway_seat *seat, |
670 | struct sway_seat_device *sway_device) { | 704 | struct sway_seat_device *sway_device) { |
671 | struct input_config *ic = | 705 | struct input_config *ic = |
@@ -681,7 +715,21 @@ static void seat_apply_input_config(struct sway_seat *seat, | |||
681 | 715 | ||
682 | switch (mapped_to) { | 716 | switch (mapped_to) { |
683 | case MAPPED_TO_DEFAULT: | 717 | case MAPPED_TO_DEFAULT: |
718 | /* | ||
719 | * If the wlroots backend provides an output name, use that. | ||
720 | * | ||
721 | * Otherwise, try to map built-in touch and tablet tool devices to the | ||
722 | * built-in output. | ||
723 | */ | ||
684 | mapped_to_output = sway_device->input_device->wlr_device->output_name; | 724 | mapped_to_output = sway_device->input_device->wlr_device->output_name; |
725 | if (mapped_to_output == NULL && is_touch_or_tablet_tool(sway_device) && | ||
726 | sway_libinput_device_is_builtin(sway_device->input_device)) { | ||
727 | mapped_to_output = get_builtin_output_name(); | ||
728 | if (mapped_to_output) { | ||
729 | sway_log(SWAY_DEBUG, "Auto-detected output '%s' for device '%s'", | ||
730 | mapped_to_output, sway_device->input_device->identifier); | ||
731 | } | ||
732 | } | ||
685 | if (mapped_to_output == NULL) { | 733 | if (mapped_to_output == NULL) { |
686 | return; | 734 | return; |
687 | } | 735 | } |
@@ -1086,30 +1134,19 @@ void seat_set_focus(struct sway_seat *seat, struct sway_node *node) { | |||
1086 | } | 1134 | } |
1087 | 1135 | ||
1088 | struct sway_workspace *new_workspace = node->type == N_WORKSPACE ? | 1136 | struct sway_workspace *new_workspace = node->type == N_WORKSPACE ? |
1089 | node->sway_workspace : node->sway_container->workspace; | 1137 | node->sway_workspace : node->sway_container->pending.workspace; |
1090 | struct sway_container *container = node->type == N_CONTAINER ? | 1138 | struct sway_container *container = node->type == N_CONTAINER ? |
1091 | node->sway_container : NULL; | 1139 | node->sway_container : NULL; |
1092 | 1140 | ||
1093 | // Deny setting focus to a view which is hidden by a fullscreen container | 1141 | // Deny setting focus to a view which is hidden by a fullscreen container or global |
1094 | if (new_workspace && new_workspace->fullscreen && container && | 1142 | if (container && container_obstructing_fullscreen_container(container)) { |
1095 | !container_is_fullscreen_or_child(container)) { | 1143 | return; |
1096 | // Unless it's a transient container | ||
1097 | if (!container_is_transient_for(container, new_workspace->fullscreen)) { | ||
1098 | return; | ||
1099 | } | ||
1100 | } | 1144 | } |
1145 | |||
1101 | // Deny setting focus to a workspace node when using fullscreen global | 1146 | // Deny setting focus to a workspace node when using fullscreen global |
1102 | if (root->fullscreen_global && !container && new_workspace) { | 1147 | if (root->fullscreen_global && !container && new_workspace) { |
1103 | return; | 1148 | return; |
1104 | } | 1149 | } |
1105 | // Deny setting focus to a view which is hidden by a fullscreen global | ||
1106 | if (root->fullscreen_global && container != root->fullscreen_global && | ||
1107 | !container_has_ancestor(container, root->fullscreen_global)) { | ||
1108 | // Unless it's a transient container | ||
1109 | if (!container_is_transient_for(container, root->fullscreen_global)) { | ||
1110 | return; | ||
1111 | } | ||
1112 | } | ||
1113 | 1150 | ||
1114 | struct sway_output *new_output = | 1151 | struct sway_output *new_output = |
1115 | new_workspace ? new_workspace->output : NULL; | 1152 | new_workspace ? new_workspace->output : NULL; |
@@ -1135,10 +1172,10 @@ void seat_set_focus(struct sway_seat *seat, struct sway_node *node) { | |||
1135 | // Put the container parents on the focus stack, then the workspace, then | 1172 | // Put the container parents on the focus stack, then the workspace, then |
1136 | // the focused container. | 1173 | // the focused container. |
1137 | if (container) { | 1174 | if (container) { |
1138 | struct sway_container *parent = container->parent; | 1175 | struct sway_container *parent = container->pending.parent; |
1139 | while (parent) { | 1176 | while (parent) { |
1140 | seat_set_raw_focus(seat, &parent->node); | 1177 | seat_set_raw_focus(seat, &parent->node); |
1141 | parent = parent->parent; | 1178 | parent = parent->pending.parent; |
1142 | } | 1179 | } |
1143 | } | 1180 | } |
1144 | if (new_workspace) { | 1181 | if (new_workspace) { |
@@ -1234,6 +1271,7 @@ void seat_set_focus_surface(struct sway_seat *seat, | |||
1234 | wlr_seat_keyboard_notify_clear_focus(seat->wlr_seat); | 1271 | wlr_seat_keyboard_notify_clear_focus(seat->wlr_seat); |
1235 | } | 1272 | } |
1236 | 1273 | ||
1274 | sway_input_method_relay_set_focus(&seat->im_relay, surface); | ||
1237 | seat_tablet_pads_notify_enter(seat, surface); | 1275 | seat_tablet_pads_notify_enter(seat, surface); |
1238 | } | 1276 | } |
1239 | 1277 | ||
@@ -1326,7 +1364,7 @@ struct sway_container *seat_get_focus_inactive_tiling(struct sway_seat *seat, | |||
1326 | struct sway_node *node = current->node; | 1364 | struct sway_node *node = current->node; |
1327 | if (node->type == N_CONTAINER && | 1365 | if (node->type == N_CONTAINER && |
1328 | !container_is_floating_or_child(node->sway_container) && | 1366 | !container_is_floating_or_child(node->sway_container) && |
1329 | node->sway_container->workspace == workspace) { | 1367 | node->sway_container->pending.workspace == workspace) { |
1330 | return node->sway_container; | 1368 | return node->sway_container; |
1331 | } | 1369 | } |
1332 | } | 1370 | } |
@@ -1343,7 +1381,7 @@ struct sway_container *seat_get_focus_inactive_floating(struct sway_seat *seat, | |||
1343 | struct sway_node *node = current->node; | 1381 | struct sway_node *node = current->node; |
1344 | if (node->type == N_CONTAINER && | 1382 | if (node->type == N_CONTAINER && |
1345 | container_is_floating_or_child(node->sway_container) && | 1383 | container_is_floating_or_child(node->sway_container) && |
1346 | node->sway_container->workspace == workspace) { | 1384 | node->sway_container->pending.workspace == workspace) { |
1347 | return node->sway_container; | 1385 | return node->sway_container; |
1348 | } | 1386 | } |
1349 | } | 1387 | } |
@@ -1391,7 +1429,7 @@ struct sway_workspace *seat_get_focused_workspace(struct sway_seat *seat) { | |||
1391 | return NULL; | 1429 | return NULL; |
1392 | } | 1430 | } |
1393 | if (focus->type == N_CONTAINER) { | 1431 | if (focus->type == N_CONTAINER) { |
1394 | return focus->sway_container->workspace; | 1432 | return focus->sway_container->pending.workspace; |
1395 | } | 1433 | } |
1396 | if (focus->type == N_WORKSPACE) { | 1434 | if (focus->type == N_WORKSPACE) { |
1397 | return focus->sway_workspace; | 1435 | return focus->sway_workspace; |
@@ -1404,8 +1442,8 @@ struct sway_workspace *seat_get_last_known_workspace(struct sway_seat *seat) { | |||
1404 | wl_list_for_each(current, &seat->focus_stack, link) { | 1442 | wl_list_for_each(current, &seat->focus_stack, link) { |
1405 | struct sway_node *node = current->node; | 1443 | struct sway_node *node = current->node; |
1406 | if (node->type == N_CONTAINER && | 1444 | if (node->type == N_CONTAINER && |
1407 | node->sway_container->workspace) { | 1445 | node->sway_container->pending.workspace) { |
1408 | return node->sway_container->workspace; | 1446 | return node->sway_container->pending.workspace; |
1409 | } else if (node->type == N_WORKSPACE) { | 1447 | } else if (node->type == N_WORKSPACE) { |
1410 | return node->sway_workspace; | 1448 | return node->sway_workspace; |
1411 | } | 1449 | } |
diff --git a/sway/input/seatop_default.c b/sway/input/seatop_default.c index a583ed62..4320a3b4 100644 --- a/sway/input/seatop_default.c +++ b/sway/input/seatop_default.c | |||
@@ -4,6 +4,7 @@ | |||
4 | #include <wlr/types/wlr_cursor.h> | 4 | #include <wlr/types/wlr_cursor.h> |
5 | #include <wlr/types/wlr_tablet_v2.h> | 5 | #include <wlr/types/wlr_tablet_v2.h> |
6 | #include <wlr/types/wlr_xcursor_manager.h> | 6 | #include <wlr/types/wlr_xcursor_manager.h> |
7 | #include "sway/desktop/transaction.h" | ||
7 | #include "sway/input/cursor.h" | 8 | #include "sway/input/cursor.h" |
8 | #include "sway/input/seat.h" | 9 | #include "sway/input/seat.h" |
9 | #include "sway/input/tablet.h" | 10 | #include "sway/input/tablet.h" |
@@ -59,7 +60,7 @@ static bool edge_is_external(struct sway_container *cont, enum wlr_edges edge) { | |||
59 | return false; | 60 | return false; |
60 | } | 61 | } |
61 | } | 62 | } |
62 | cont = cont->parent; | 63 | cont = cont->pending.parent; |
63 | } | 64 | } |
64 | return true; | 65 | return true; |
65 | } | 66 | } |
@@ -69,25 +70,25 @@ static enum wlr_edges find_edge(struct sway_container *cont, | |||
69 | if (!cont->view || (surface && cont->view->surface != surface)) { | 70 | if (!cont->view || (surface && cont->view->surface != surface)) { |
70 | return WLR_EDGE_NONE; | 71 | return WLR_EDGE_NONE; |
71 | } | 72 | } |
72 | if (cont->border == B_NONE || !cont->border_thickness || | 73 | if (cont->pending.border == B_NONE || !cont->pending.border_thickness || |
73 | cont->border == B_CSD) { | 74 | cont->pending.border == B_CSD) { |
74 | return WLR_EDGE_NONE; | 75 | return WLR_EDGE_NONE; |
75 | } | 76 | } |
76 | if (cont->fullscreen_mode) { | 77 | if (cont->pending.fullscreen_mode) { |
77 | return WLR_EDGE_NONE; | 78 | return WLR_EDGE_NONE; |
78 | } | 79 | } |
79 | 80 | ||
80 | enum wlr_edges edge = 0; | 81 | enum wlr_edges edge = 0; |
81 | if (cursor->cursor->x < cont->x + cont->border_thickness) { | 82 | if (cursor->cursor->x < cont->pending.x + cont->pending.border_thickness) { |
82 | edge |= WLR_EDGE_LEFT; | 83 | edge |= WLR_EDGE_LEFT; |
83 | } | 84 | } |
84 | if (cursor->cursor->y < cont->y + cont->border_thickness) { | 85 | if (cursor->cursor->y < cont->pending.y + cont->pending.border_thickness) { |
85 | edge |= WLR_EDGE_TOP; | 86 | edge |= WLR_EDGE_TOP; |
86 | } | 87 | } |
87 | if (cursor->cursor->x >= cont->x + cont->width - cont->border_thickness) { | 88 | if (cursor->cursor->x >= cont->pending.x + cont->pending.width - cont->pending.border_thickness) { |
88 | edge |= WLR_EDGE_RIGHT; | 89 | edge |= WLR_EDGE_RIGHT; |
89 | } | 90 | } |
90 | if (cursor->cursor->y >= cont->y + cont->height - cont->border_thickness) { | 91 | if (cursor->cursor->y >= cont->pending.y + cont->pending.height - cont->pending.border_thickness) { |
91 | edge |= WLR_EDGE_BOTTOM; | 92 | edge |= WLR_EDGE_BOTTOM; |
92 | } | 93 | } |
93 | 94 | ||
@@ -231,6 +232,7 @@ static void handle_tablet_tool_tip(struct sway_seat *seat, | |||
231 | wlr_layer_surface_v1_from_wlr_surface(surface); | 232 | wlr_layer_surface_v1_from_wlr_surface(surface); |
232 | if (layer->current.keyboard_interactive) { | 233 | if (layer->current.keyboard_interactive) { |
233 | seat_set_focus_layer(seat, layer); | 234 | seat_set_focus_layer(seat, layer); |
235 | transaction_commit_dirty(); | ||
234 | } | 236 | } |
235 | } else if (cont) { | 237 | } else if (cont) { |
236 | bool is_floating_or_child = container_is_floating_or_child(cont); | 238 | bool is_floating_or_child = container_is_floating_or_child(cont); |
@@ -249,7 +251,7 @@ static void handle_tablet_tool_tip(struct sway_seat *seat, | |||
249 | 251 | ||
250 | // Handle moving a tiling container | 252 | // Handle moving a tiling container |
251 | if (config->tiling_drag && mod_pressed && !is_floating_or_child && | 253 | if (config->tiling_drag && mod_pressed && !is_floating_or_child && |
252 | cont->fullscreen_mode == FULLSCREEN_NONE) { | 254 | cont->pending.fullscreen_mode == FULLSCREEN_NONE) { |
253 | seatop_begin_move_tiling(seat, cont); | 255 | seatop_begin_move_tiling(seat, cont); |
254 | return; | 256 | return; |
255 | } | 257 | } |
@@ -268,6 +270,7 @@ static void handle_tablet_tool_tip(struct sway_seat *seat, | |||
268 | struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; | 270 | struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; |
269 | wlr_xwayland_set_seat(xwayland, seat->wlr_seat); | 271 | wlr_xwayland_set_seat(xwayland, seat->wlr_seat); |
270 | seat_set_focus_surface(seat, xsurface->surface, false); | 272 | seat_set_focus_surface(seat, xsurface->surface, false); |
273 | transaction_commit_dirty(); | ||
271 | } | 274 | } |
272 | } | 275 | } |
273 | #endif | 276 | #endif |
@@ -356,6 +359,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
356 | if (node && node->type == N_WORKSPACE) { | 359 | if (node && node->type == N_WORKSPACE) { |
357 | if (state == WLR_BUTTON_PRESSED) { | 360 | if (state == WLR_BUTTON_PRESSED) { |
358 | seat_set_focus(seat, node); | 361 | seat_set_focus(seat, node); |
362 | transaction_commit_dirty(); | ||
359 | } | 363 | } |
360 | seat_pointer_notify_button(seat, time_msec, button, state); | 364 | seat_pointer_notify_button(seat, time_msec, button, state); |
361 | return; | 365 | return; |
@@ -367,6 +371,10 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
367 | wlr_layer_surface_v1_from_wlr_surface(surface); | 371 | wlr_layer_surface_v1_from_wlr_surface(surface); |
368 | if (layer->current.keyboard_interactive) { | 372 | if (layer->current.keyboard_interactive) { |
369 | seat_set_focus_layer(seat, layer); | 373 | seat_set_focus_layer(seat, layer); |
374 | transaction_commit_dirty(); | ||
375 | } | ||
376 | if (state == WLR_BUTTON_PRESSED) { | ||
377 | seatop_begin_down_on_surface(seat, surface, time_msec, sx, sy); | ||
370 | } | 378 | } |
371 | seat_pointer_notify_button(seat, time_msec, button, state); | 379 | seat_pointer_notify_button(seat, time_msec, button, state); |
372 | return; | 380 | return; |
@@ -381,7 +389,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
381 | struct sway_container *cont_to_focus = cont; | 389 | struct sway_container *cont_to_focus = cont; |
382 | enum sway_container_layout layout = container_parent_layout(cont); | 390 | enum sway_container_layout layout = container_parent_layout(cont); |
383 | if (layout == L_TABBED || layout == L_STACKED) { | 391 | if (layout == L_TABBED || layout == L_STACKED) { |
384 | cont_to_focus = seat_get_focus_inactive_view(seat, &cont->parent->node); | 392 | cont_to_focus = seat_get_focus_inactive_view(seat, &cont->pending.parent->node); |
385 | } | 393 | } |
386 | 394 | ||
387 | seat_set_focus_container(seat, cont_to_focus); | 395 | seat_set_focus_container(seat, cont_to_focus); |
@@ -397,9 +405,9 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
397 | BTN_LEFT : BTN_RIGHT; | 405 | BTN_LEFT : BTN_RIGHT; |
398 | if (button == btn_resize) { | 406 | if (button == btn_resize) { |
399 | edge = 0; | 407 | edge = 0; |
400 | edge |= cursor->cursor->x > cont->x + cont->width / 2 ? | 408 | edge |= cursor->cursor->x > cont->pending.x + cont->pending.width / 2 ? |
401 | WLR_EDGE_RIGHT : WLR_EDGE_LEFT; | 409 | WLR_EDGE_RIGHT : WLR_EDGE_LEFT; |
402 | edge |= cursor->cursor->y > cont->y + cont->height / 2 ? | 410 | edge |= cursor->cursor->y > cont->pending.y + cont->pending.height / 2 ? |
403 | WLR_EDGE_BOTTOM : WLR_EDGE_TOP; | 411 | WLR_EDGE_BOTTOM : WLR_EDGE_TOP; |
404 | 412 | ||
405 | const char *image = NULL; | 413 | const char *image = NULL; |
@@ -446,9 +454,9 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
446 | if (mod_pressed && button == btn_resize) { | 454 | if (mod_pressed && button == btn_resize) { |
447 | struct sway_container *floater = container_toplevel_ancestor(cont); | 455 | struct sway_container *floater = container_toplevel_ancestor(cont); |
448 | edge = 0; | 456 | edge = 0; |
449 | edge |= cursor->cursor->x > floater->x + floater->width / 2 ? | 457 | edge |= cursor->cursor->x > floater->pending.x + floater->pending.width / 2 ? |
450 | WLR_EDGE_RIGHT : WLR_EDGE_LEFT; | 458 | WLR_EDGE_RIGHT : WLR_EDGE_LEFT; |
451 | edge |= cursor->cursor->y > floater->y + floater->height / 2 ? | 459 | edge |= cursor->cursor->y > floater->pending.y + floater->pending.height / 2 ? |
452 | WLR_EDGE_BOTTOM : WLR_EDGE_TOP; | 460 | WLR_EDGE_BOTTOM : WLR_EDGE_TOP; |
453 | seatop_begin_resize_floating(seat, floater, edge); | 461 | seatop_begin_resize_floating(seat, floater, edge); |
454 | return; | 462 | return; |
@@ -458,7 +466,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
458 | // Handle moving a tiling container | 466 | // Handle moving a tiling container |
459 | if (config->tiling_drag && (mod_pressed || on_titlebar) && | 467 | if (config->tiling_drag && (mod_pressed || on_titlebar) && |
460 | state == WLR_BUTTON_PRESSED && !is_floating_or_child && | 468 | state == WLR_BUTTON_PRESSED && !is_floating_or_child && |
461 | cont && cont->fullscreen_mode == FULLSCREEN_NONE) { | 469 | cont && cont->pending.fullscreen_mode == FULLSCREEN_NONE) { |
462 | struct sway_container *focus = seat_get_focused_container(seat); | 470 | struct sway_container *focus = seat_get_focused_container(seat); |
463 | bool focused = focus == cont || container_has_ancestor(focus, cont); | 471 | bool focused = focus == cont || container_has_ancestor(focus, cont); |
464 | if (on_titlebar && !focused) { | 472 | if (on_titlebar && !focused) { |
@@ -487,6 +495,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
487 | if (cont && state == WLR_BUTTON_PRESSED) { | 495 | if (cont && state == WLR_BUTTON_PRESSED) { |
488 | node = seat_get_focus_inactive(seat, &cont->node); | 496 | node = seat_get_focus_inactive(seat, &cont->node); |
489 | seat_set_focus(seat, node); | 497 | seat_set_focus(seat, node); |
498 | transaction_commit_dirty(); | ||
490 | seat_pointer_notify_button(seat, time_msec, button, state); | 499 | seat_pointer_notify_button(seat, time_msec, button, state); |
491 | return; | 500 | return; |
492 | } | 501 | } |
@@ -501,6 +510,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
501 | struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; | 510 | struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland; |
502 | wlr_xwayland_set_seat(xwayland, seat->wlr_seat); | 511 | wlr_xwayland_set_seat(xwayland, seat->wlr_seat); |
503 | seat_set_focus_surface(seat, xsurface->surface, false); | 512 | seat_set_focus_surface(seat, xsurface->surface, false); |
513 | transaction_commit_dirty(); | ||
504 | seat_pointer_notify_button(seat, time_msec, button, state); | 514 | seat_pointer_notify_button(seat, time_msec, button, state); |
505 | return; | 515 | return; |
506 | } | 516 | } |
@@ -530,6 +540,7 @@ static void check_focus_follows_mouse(struct sway_seat *seat, | |||
530 | if (focus && hovered_output != node_get_output(focus)) { | 540 | if (focus && hovered_output != node_get_output(focus)) { |
531 | struct sway_workspace *ws = output_get_active_workspace(hovered_output); | 541 | struct sway_workspace *ws = output_get_active_workspace(hovered_output); |
532 | seat_set_focus(seat, &ws->node); | 542 | seat_set_focus(seat, &ws->node); |
543 | transaction_commit_dirty(); | ||
533 | } | 544 | } |
534 | return; | 545 | return; |
535 | } | 546 | } |
@@ -541,6 +552,7 @@ static void check_focus_follows_mouse(struct sway_seat *seat, | |||
541 | struct sway_output *hovered_output = node_get_output(hovered_node); | 552 | struct sway_output *hovered_output = node_get_output(hovered_node); |
542 | if (hovered_output != focused_output) { | 553 | if (hovered_output != focused_output) { |
543 | seat_set_focus(seat, seat_get_focus_inactive(seat, hovered_node)); | 554 | seat_set_focus(seat, seat_get_focus_inactive(seat, hovered_node)); |
555 | transaction_commit_dirty(); | ||
544 | } | 556 | } |
545 | return; | 557 | return; |
546 | } | 558 | } |
@@ -556,6 +568,7 @@ static void check_focus_follows_mouse(struct sway_seat *seat, | |||
556 | if (hovered_node != e->previous_node || | 568 | if (hovered_node != e->previous_node || |
557 | config->focus_follows_mouse == FOLLOWS_ALWAYS) { | 569 | config->focus_follows_mouse == FOLLOWS_ALWAYS) { |
558 | seat_set_focus(seat, hovered_node); | 570 | seat_set_focus(seat, hovered_node); |
571 | transaction_commit_dirty(); | ||
559 | } | 572 | } |
560 | } | 573 | } |
561 | } | 574 | } |
@@ -664,7 +677,7 @@ static void handle_pointer_axis(struct sway_seat *seat, | |||
664 | bool on_border = edge != WLR_EDGE_NONE; | 677 | bool on_border = edge != WLR_EDGE_NONE; |
665 | bool on_titlebar = cont && !on_border && !surface; | 678 | bool on_titlebar = cont && !on_border && !surface; |
666 | bool on_titlebar_border = cont && on_border && | 679 | bool on_titlebar_border = cont && on_border && |
667 | cursor->cursor->y < cont->content_y; | 680 | cursor->cursor->y < cont->pending.content_y; |
668 | bool on_contents = cont && !on_border && surface; | 681 | bool on_contents = cont && !on_border && surface; |
669 | bool on_workspace = node && node->type == N_WORKSPACE; | 682 | bool on_workspace = node && node->type == N_WORKSPACE; |
670 | float scroll_factor = | 683 | float scroll_factor = |
@@ -714,6 +727,7 @@ static void handle_pointer_axis(struct sway_seat *seat, | |||
714 | // Use the focused child of the tabbed/stacked container, not the | 727 | // Use the focused child of the tabbed/stacked container, not the |
715 | // container the user scrolled on. | 728 | // container the user scrolled on. |
716 | seat_set_focus(seat, new_focus); | 729 | seat_set_focus(seat, new_focus); |
730 | transaction_commit_dirty(); | ||
717 | handled = true; | 731 | handled = true; |
718 | } | 732 | } |
719 | } | 733 | } |
diff --git a/sway/input/seatop_down.c b/sway/input/seatop_down.c index 17f619e3..ecc34fea 100644 --- a/sway/input/seatop_down.c +++ b/sway/input/seatop_down.c | |||
@@ -5,10 +5,14 @@ | |||
5 | #include "sway/input/cursor.h" | 5 | #include "sway/input/cursor.h" |
6 | #include "sway/input/seat.h" | 6 | #include "sway/input/seat.h" |
7 | #include "sway/tree/view.h" | 7 | #include "sway/tree/view.h" |
8 | #include "sway/desktop/transaction.h" | ||
8 | #include "log.h" | 9 | #include "log.h" |
9 | 10 | ||
10 | struct seatop_down_event { | 11 | struct seatop_down_event { |
11 | struct sway_container *con; | 12 | struct sway_container *con; |
13 | struct sway_seat *seat; | ||
14 | struct wl_listener surface_destroy; | ||
15 | struct wlr_surface *surface; | ||
12 | double ref_lx, ref_ly; // cursor's x/y at start of op | 16 | double ref_lx, ref_ly; // cursor's x/y at start of op |
13 | double ref_con_lx, ref_con_ly; // container's x/y at start of op | 17 | double ref_con_lx, ref_con_ly; // container's x/y at start of op |
14 | }; | 18 | }; |
@@ -39,8 +43,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
39 | 43 | ||
40 | static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) { | 44 | static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) { |
41 | struct seatop_down_event *e = seat->seatop_data; | 45 | struct seatop_down_event *e = seat->seatop_data; |
42 | struct sway_container *con = e->con; | 46 | if (seat_is_input_allowed(seat, e->surface)) { |
43 | if (seat_is_input_allowed(seat, con->view->surface)) { | ||
44 | double moved_x = seat->cursor->cursor->x - e->ref_lx; | 47 | double moved_x = seat->cursor->cursor->x - e->ref_lx; |
45 | double moved_y = seat->cursor->cursor->y - e->ref_ly; | 48 | double moved_y = seat->cursor->cursor->y - e->ref_ly; |
46 | double sx = e->ref_con_lx + moved_x; | 49 | double sx = e->ref_con_lx + moved_x; |
@@ -61,8 +64,7 @@ static void handle_tablet_tool_tip(struct sway_seat *seat, | |||
61 | static void handle_tablet_tool_motion(struct sway_seat *seat, | 64 | static void handle_tablet_tool_motion(struct sway_seat *seat, |
62 | struct sway_tablet_tool *tool, uint32_t time_msec) { | 65 | struct sway_tablet_tool *tool, uint32_t time_msec) { |
63 | struct seatop_down_event *e = seat->seatop_data; | 66 | struct seatop_down_event *e = seat->seatop_data; |
64 | struct sway_container *con = e->con; | 67 | if (seat_is_input_allowed(seat, e->surface)) { |
65 | if (seat_is_input_allowed(seat, con->view->surface)) { | ||
66 | double moved_x = seat->cursor->cursor->x - e->ref_lx; | 68 | double moved_x = seat->cursor->cursor->x - e->ref_lx; |
67 | double moved_y = seat->cursor->cursor->y - e->ref_ly; | 69 | double moved_y = seat->cursor->cursor->y - e->ref_ly; |
68 | double sx = e->ref_con_lx + moved_x; | 70 | double sx = e->ref_con_lx + moved_x; |
@@ -71,6 +73,14 @@ static void handle_tablet_tool_motion(struct sway_seat *seat, | |||
71 | } | 73 | } |
72 | } | 74 | } |
73 | 75 | ||
76 | static void handle_destroy(struct wl_listener *listener, void *data) { | ||
77 | struct seatop_down_event *e = | ||
78 | wl_container_of(listener, e, surface_destroy); | ||
79 | if (e) { | ||
80 | seatop_begin_default(e->seat); | ||
81 | } | ||
82 | } | ||
83 | |||
74 | static void handle_unref(struct sway_seat *seat, struct sway_container *con) { | 84 | static void handle_unref(struct sway_seat *seat, struct sway_container *con) { |
75 | struct seatop_down_event *e = seat->seatop_data; | 85 | struct seatop_down_event *e = seat->seatop_data; |
76 | if (e->con == con) { | 86 | if (e->con == con) { |
@@ -78,6 +88,11 @@ static void handle_unref(struct sway_seat *seat, struct sway_container *con) { | |||
78 | } | 88 | } |
79 | } | 89 | } |
80 | 90 | ||
91 | static void handle_end(struct sway_seat *seat) { | ||
92 | struct seatop_down_event *e = seat->seatop_data; | ||
93 | wl_list_remove(&e->surface_destroy.link); | ||
94 | } | ||
95 | |||
81 | static const struct sway_seatop_impl seatop_impl = { | 96 | static const struct sway_seatop_impl seatop_impl = { |
82 | .button = handle_button, | 97 | .button = handle_button, |
83 | .pointer_motion = handle_pointer_motion, | 98 | .pointer_motion = handle_pointer_motion, |
@@ -85,11 +100,22 @@ static const struct sway_seatop_impl seatop_impl = { | |||
85 | .tablet_tool_tip = handle_tablet_tool_tip, | 100 | .tablet_tool_tip = handle_tablet_tool_tip, |
86 | .tablet_tool_motion = handle_tablet_tool_motion, | 101 | .tablet_tool_motion = handle_tablet_tool_motion, |
87 | .unref = handle_unref, | 102 | .unref = handle_unref, |
103 | .end = handle_end, | ||
88 | .allow_set_cursor = true, | 104 | .allow_set_cursor = true, |
89 | }; | 105 | }; |
90 | 106 | ||
91 | void seatop_begin_down(struct sway_seat *seat, struct sway_container *con, | 107 | void seatop_begin_down(struct sway_seat *seat, struct sway_container *con, |
92 | uint32_t time_msec, int sx, int sy) { | 108 | uint32_t time_msec, double sx, double sy) { |
109 | seatop_begin_down_on_surface(seat, con->view->surface, time_msec, sx, sy); | ||
110 | struct seatop_down_event *e = seat->seatop_data; | ||
111 | e->con = con; | ||
112 | |||
113 | container_raise_floating(con); | ||
114 | transaction_commit_dirty(); | ||
115 | } | ||
116 | |||
117 | void seatop_begin_down_on_surface(struct sway_seat *seat, | ||
118 | struct wlr_surface *surface, uint32_t time_msec, double sx, double sy) { | ||
93 | seatop_end(seat); | 119 | seatop_end(seat); |
94 | 120 | ||
95 | struct seatop_down_event *e = | 121 | struct seatop_down_event *e = |
@@ -97,7 +123,11 @@ void seatop_begin_down(struct sway_seat *seat, struct sway_container *con, | |||
97 | if (!e) { | 123 | if (!e) { |
98 | return; | 124 | return; |
99 | } | 125 | } |
100 | e->con = con; | 126 | e->con = NULL; |
127 | e->seat = seat; | ||
128 | e->surface = surface; | ||
129 | wl_signal_add(&e->surface->events.destroy, &e->surface_destroy); | ||
130 | e->surface_destroy.notify = handle_destroy; | ||
101 | e->ref_lx = seat->cursor->cursor->x; | 131 | e->ref_lx = seat->cursor->cursor->x; |
102 | e->ref_ly = seat->cursor->cursor->y; | 132 | e->ref_ly = seat->cursor->cursor->y; |
103 | e->ref_con_lx = sx; | 133 | e->ref_con_lx = sx; |
@@ -105,6 +135,4 @@ void seatop_begin_down(struct sway_seat *seat, struct sway_container *con, | |||
105 | 135 | ||
106 | seat->seatop_impl = &seatop_impl; | 136 | seat->seatop_impl = &seatop_impl; |
107 | seat->seatop_data = e; | 137 | seat->seatop_data = e; |
108 | |||
109 | container_raise_floating(con); | ||
110 | } | 138 | } |
diff --git a/sway/input/seatop_move_floating.c b/sway/input/seatop_move_floating.c index 7f501fc9..ddcd4c53 100644 --- a/sway/input/seatop_move_floating.c +++ b/sway/input/seatop_move_floating.c | |||
@@ -1,6 +1,7 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | 1 | #define _POSIX_C_SOURCE 200809L |
2 | #include <wlr/types/wlr_cursor.h> | 2 | #include <wlr/types/wlr_cursor.h> |
3 | #include "sway/desktop.h" | 3 | #include "sway/desktop.h" |
4 | #include "sway/desktop/transaction.h" | ||
4 | #include "sway/input/cursor.h" | 5 | #include "sway/input/cursor.h" |
5 | #include "sway/input/seat.h" | 6 | #include "sway/input/seat.h" |
6 | 7 | ||
@@ -14,7 +15,8 @@ static void finalize_move(struct sway_seat *seat) { | |||
14 | 15 | ||
15 | // We "move" the container to its own location | 16 | // We "move" the container to its own location |
16 | // so it discovers its output again. | 17 | // so it discovers its output again. |
17 | container_floating_move_to(e->con, e->con->x, e->con->y); | 18 | container_floating_move_to(e->con, e->con->pending.x, e->con->pending.y); |
19 | transaction_commit_dirty(); | ||
18 | 20 | ||
19 | seatop_begin_default(seat); | 21 | seatop_begin_default(seat); |
20 | } | 22 | } |
@@ -40,6 +42,7 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) { | |||
40 | desktop_damage_whole_container(e->con); | 42 | desktop_damage_whole_container(e->con); |
41 | container_floating_move_to(e->con, cursor->x - e->dx, cursor->y - e->dy); | 43 | container_floating_move_to(e->con, cursor->x - e->dx, cursor->y - e->dy); |
42 | desktop_damage_whole_container(e->con); | 44 | desktop_damage_whole_container(e->con); |
45 | transaction_commit_dirty(); | ||
43 | } | 46 | } |
44 | 47 | ||
45 | static void handle_unref(struct sway_seat *seat, struct sway_container *con) { | 48 | static void handle_unref(struct sway_seat *seat, struct sway_container *con) { |
@@ -67,13 +70,14 @@ void seatop_begin_move_floating(struct sway_seat *seat, | |||
67 | return; | 70 | return; |
68 | } | 71 | } |
69 | e->con = con; | 72 | e->con = con; |
70 | e->dx = cursor->cursor->x - con->x; | 73 | e->dx = cursor->cursor->x - con->pending.x; |
71 | e->dy = cursor->cursor->y - con->y; | 74 | e->dy = cursor->cursor->y - con->pending.y; |
72 | 75 | ||
73 | seat->seatop_impl = &seatop_impl; | 76 | seat->seatop_impl = &seatop_impl; |
74 | seat->seatop_data = e; | 77 | seat->seatop_data = e; |
75 | 78 | ||
76 | container_raise_floating(con); | 79 | container_raise_floating(con); |
80 | transaction_commit_dirty(); | ||
77 | 81 | ||
78 | cursor_set_image(cursor, "grab", NULL); | 82 | cursor_set_image(cursor, "grab", NULL); |
79 | wlr_seat_pointer_notify_clear_focus(seat->wlr_seat); | 83 | 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 704e7270..223c6c08 100644 --- a/sway/input/seatop_move_tiling.c +++ b/sway/input/seatop_move_tiling.c | |||
@@ -3,6 +3,7 @@ | |||
3 | #include <wlr/types/wlr_cursor.h> | 3 | #include <wlr/types/wlr_cursor.h> |
4 | #include <wlr/util/edges.h> | 4 | #include <wlr/util/edges.h> |
5 | #include "sway/desktop.h" | 5 | #include "sway/desktop.h" |
6 | #include "sway/desktop/transaction.h" | ||
6 | #include "sway/input/cursor.h" | 7 | #include "sway/input/cursor.h" |
7 | #include "sway/input/seat.h" | 8 | #include "sway/input/seat.h" |
8 | #include "sway/ipc-server.h" | 9 | #include "sway/ipc-server.h" |
@@ -15,6 +16,10 @@ | |||
15 | // Thickness of the dropzone when dragging to the edge of a layout container | 16 | // Thickness of the dropzone when dragging to the edge of a layout container |
16 | #define DROP_LAYOUT_BORDER 30 | 17 | #define DROP_LAYOUT_BORDER 30 |
17 | 18 | ||
19 | // Thickness of indicator when dropping onto a titlebar. This should be a | ||
20 | // multiple of 2. | ||
21 | #define DROP_SPLIT_INDICATOR 10 | ||
22 | |||
18 | struct seatop_move_tiling_event { | 23 | struct seatop_move_tiling_event { |
19 | struct sway_container *con; | 24 | struct sway_container *con; |
20 | struct sway_node *target_node; | 25 | struct sway_node *target_node; |
@@ -22,6 +27,8 @@ struct seatop_move_tiling_event { | |||
22 | struct wlr_box drop_box; | 27 | struct wlr_box drop_box; |
23 | double ref_lx, ref_ly; // cursor's x/y at start of op | 28 | double ref_lx, ref_ly; // cursor's x/y at start of op |
24 | bool threshold_reached; | 29 | bool threshold_reached; |
30 | bool split_target; | ||
31 | bool insert_after_target; | ||
25 | }; | 32 | }; |
26 | 33 | ||
27 | static void handle_render(struct sway_seat *seat, | 34 | static void handle_render(struct sway_seat *seat, |
@@ -91,8 +98,76 @@ static void resize_box(struct wlr_box *box, enum wlr_edges edge, | |||
91 | } | 98 | } |
92 | } | 99 | } |
93 | 100 | ||
101 | static void split_border(double pos, int offset, int len, int n_children, | ||
102 | int avoid, int *out_pos, bool *out_after) { | ||
103 | int region = 2 * n_children * (pos - offset) / len; | ||
104 | // If the cursor is over the right side of a left-adjacent titlebar, or the | ||
105 | // left side of a right-adjacent titlebar, it's position when dropped will | ||
106 | // be the same. To avoid this, shift the region for adjacent containers. | ||
107 | if (avoid >= 0) { | ||
108 | if (region == 2 * avoid - 1 || region == 2 * avoid) { | ||
109 | region--; | ||
110 | } else if (region == 2 * avoid + 1 || region == 2 * avoid + 2) { | ||
111 | region++; | ||
112 | } | ||
113 | } | ||
114 | |||
115 | int child_index = (region + 1) / 2; | ||
116 | *out_after = region % 2; | ||
117 | // When dropping at the beginning or end of a container, show the drop | ||
118 | // region within the container boundary, otherwise show it on top of the | ||
119 | // border between two titlebars. | ||
120 | if (child_index == 0) { | ||
121 | *out_pos = offset; | ||
122 | } else if (child_index == n_children) { | ||
123 | *out_pos = offset + len - DROP_SPLIT_INDICATOR; | ||
124 | } else { | ||
125 | *out_pos = offset + child_index * len / n_children - | ||
126 | DROP_SPLIT_INDICATOR / 2; | ||
127 | } | ||
128 | } | ||
129 | |||
130 | static bool split_titlebar(struct sway_node *node, struct sway_container *avoid, | ||
131 | struct wlr_cursor *cursor, struct wlr_box *title_box, bool *after) { | ||
132 | struct sway_container *con = node->sway_container; | ||
133 | struct sway_node *parent = &con->pending.parent->node; | ||
134 | int title_height = container_titlebar_height(); | ||
135 | struct wlr_box box; | ||
136 | int n_children, avoid_index; | ||
137 | enum sway_container_layout layout = | ||
138 | parent ? node_get_layout(parent) : L_NONE; | ||
139 | if (layout == L_TABBED || layout == L_STACKED) { | ||
140 | node_get_box(parent, &box); | ||
141 | n_children = node_get_children(parent)->length; | ||
142 | avoid_index = list_find(node_get_children(parent), avoid); | ||
143 | } else { | ||
144 | node_get_box(node, &box); | ||
145 | n_children = 1; | ||
146 | avoid_index = -1; | ||
147 | } | ||
148 | if (layout == L_STACKED && cursor->y < box.y + title_height * n_children) { | ||
149 | // Drop into stacked titlebars. | ||
150 | title_box->width = box.width; | ||
151 | title_box->height = DROP_SPLIT_INDICATOR; | ||
152 | title_box->x = box.x; | ||
153 | split_border(cursor->y, box.y, title_height * n_children, | ||
154 | n_children, avoid_index, &title_box->y, after); | ||
155 | return true; | ||
156 | } else if (layout != L_STACKED && cursor->y < box.y + title_height) { | ||
157 | // Drop into side-by-side titlebars. | ||
158 | title_box->width = DROP_SPLIT_INDICATOR; | ||
159 | title_box->height = title_height; | ||
160 | title_box->y = box.y; | ||
161 | split_border(cursor->x, box.x, box.width, n_children, | ||
162 | avoid_index, &title_box->x, after); | ||
163 | return true; | ||
164 | } | ||
165 | return false; | ||
166 | } | ||
167 | |||
94 | static void handle_motion_postthreshold(struct sway_seat *seat) { | 168 | static void handle_motion_postthreshold(struct sway_seat *seat) { |
95 | struct seatop_move_tiling_event *e = seat->seatop_data; | 169 | struct seatop_move_tiling_event *e = seat->seatop_data; |
170 | e->split_target = false; | ||
96 | struct wlr_surface *surface = NULL; | 171 | struct wlr_surface *surface = NULL; |
97 | double sx, sy; | 172 | double sx, sy; |
98 | struct sway_cursor *cursor = seat->cursor; | 173 | struct sway_cursor *cursor = seat->cursor; |
@@ -119,34 +194,60 @@ static void handle_motion_postthreshold(struct sway_seat *seat) { | |||
119 | 194 | ||
120 | // Deny moving within own workspace if this is the only child | 195 | // Deny moving within own workspace if this is the only child |
121 | struct sway_container *con = node->sway_container; | 196 | struct sway_container *con = node->sway_container; |
122 | if (workspace_num_tiling_views(e->con->workspace) == 1 && | 197 | if (workspace_num_tiling_views(e->con->pending.workspace) == 1 && |
123 | con->workspace == e->con->workspace) { | 198 | con->pending.workspace == e->con->pending.workspace) { |
124 | e->target_node = NULL; | 199 | e->target_node = NULL; |
125 | e->target_edge = WLR_EDGE_NONE; | 200 | e->target_edge = WLR_EDGE_NONE; |
126 | return; | 201 | return; |
127 | } | 202 | } |
128 | 203 | ||
204 | // Check if the cursor is over a tilebar only if the destination | ||
205 | // container is not a descendant of the source container. | ||
206 | if (!surface && !container_has_ancestor(con, e->con) && | ||
207 | split_titlebar(node, e->con, cursor->cursor, | ||
208 | &e->drop_box, &e->insert_after_target)) { | ||
209 | // Don't allow dropping over the source container's titlebar | ||
210 | // to give users a chance to cancel a drag operation. | ||
211 | if (con == e->con) { | ||
212 | e->target_node = NULL; | ||
213 | } else { | ||
214 | e->target_node = node; | ||
215 | e->split_target = true; | ||
216 | } | ||
217 | e->target_edge = WLR_EDGE_NONE; | ||
218 | return; | ||
219 | } | ||
220 | |||
129 | // Traverse the ancestors, trying to find a layout container perpendicular | 221 | // Traverse the ancestors, trying to find a layout container perpendicular |
130 | // to the edge. Eg. close to the top or bottom of a horiz layout. | 222 | // to the edge. Eg. close to the top or bottom of a horiz layout. |
223 | int thresh_top = con->pending.content_y + DROP_LAYOUT_BORDER; | ||
224 | int thresh_bottom = con->pending.content_y + | ||
225 | con->pending.content_height - DROP_LAYOUT_BORDER; | ||
226 | int thresh_left = con->pending.content_x + DROP_LAYOUT_BORDER; | ||
227 | int thresh_right = con->pending.content_x + | ||
228 | con->pending.content_width - DROP_LAYOUT_BORDER; | ||
131 | while (con) { | 229 | while (con) { |
132 | enum wlr_edges edge = WLR_EDGE_NONE; | 230 | enum wlr_edges edge = WLR_EDGE_NONE; |
133 | enum sway_container_layout layout = container_parent_layout(con); | 231 | enum sway_container_layout layout = container_parent_layout(con); |
134 | struct wlr_box parent; | 232 | struct wlr_box box; |
135 | con->parent ? container_get_box(con->parent, &parent) : | 233 | node_get_box(node_get_parent(&con->node), &box); |
136 | workspace_get_box(con->workspace, &parent); | ||
137 | if (layout == L_HORIZ || layout == L_TABBED) { | 234 | if (layout == L_HORIZ || layout == L_TABBED) { |
138 | if (cursor->cursor->y < parent.y + DROP_LAYOUT_BORDER) { | 235 | if (cursor->cursor->y < thresh_top) { |
139 | edge = WLR_EDGE_TOP; | 236 | edge = WLR_EDGE_TOP; |
140 | } else if (cursor->cursor->y > parent.y + parent.height | 237 | box.height = thresh_top - box.y; |
141 | - DROP_LAYOUT_BORDER) { | 238 | } else if (cursor->cursor->y > thresh_bottom) { |
142 | edge = WLR_EDGE_BOTTOM; | 239 | edge = WLR_EDGE_BOTTOM; |
240 | box.height = box.y + box.height - thresh_bottom; | ||
241 | box.y = thresh_bottom; | ||
143 | } | 242 | } |
144 | } else if (layout == L_VERT || layout == L_STACKED) { | 243 | } else if (layout == L_VERT || layout == L_STACKED) { |
145 | if (cursor->cursor->x < parent.x + DROP_LAYOUT_BORDER) { | 244 | if (cursor->cursor->x < thresh_left) { |
146 | edge = WLR_EDGE_LEFT; | 245 | edge = WLR_EDGE_LEFT; |
147 | } else if (cursor->cursor->x > parent.x + parent.width | 246 | box.width = thresh_left - box.x; |
148 | - DROP_LAYOUT_BORDER) { | 247 | } else if (cursor->cursor->x > thresh_right) { |
149 | edge = WLR_EDGE_RIGHT; | 248 | edge = WLR_EDGE_RIGHT; |
249 | box.width = box.x + box.width - thresh_right; | ||
250 | box.x = thresh_right; | ||
150 | } | 251 | } |
151 | } | 252 | } |
152 | if (edge) { | 253 | if (edge) { |
@@ -155,12 +256,11 @@ static void handle_motion_postthreshold(struct sway_seat *seat) { | |||
155 | e->target_node = node_get_parent(e->target_node); | 256 | e->target_node = node_get_parent(e->target_node); |
156 | } | 257 | } |
157 | e->target_edge = edge; | 258 | e->target_edge = edge; |
158 | node_get_box(e->target_node, &e->drop_box); | 259 | e->drop_box = box; |
159 | resize_box(&e->drop_box, edge, DROP_LAYOUT_BORDER); | ||
160 | desktop_damage_box(&e->drop_box); | 260 | desktop_damage_box(&e->drop_box); |
161 | return; | 261 | return; |
162 | } | 262 | } |
163 | con = con->parent; | 263 | con = con->pending.parent; |
164 | } | 264 | } |
165 | 265 | ||
166 | // Use the hovered view - but we must be over the actual surface | 266 | // Use the hovered view - but we must be over the actual surface |
@@ -173,23 +273,23 @@ static void handle_motion_postthreshold(struct sway_seat *seat) { | |||
173 | } | 273 | } |
174 | 274 | ||
175 | // Find the closest edge | 275 | // Find the closest edge |
176 | size_t thickness = fmin(con->content_width, con->content_height) * 0.3; | 276 | size_t thickness = fmin(con->pending.content_width, con->pending.content_height) * 0.3; |
177 | size_t closest_dist = INT_MAX; | 277 | size_t closest_dist = INT_MAX; |
178 | size_t dist; | 278 | size_t dist; |
179 | e->target_edge = WLR_EDGE_NONE; | 279 | e->target_edge = WLR_EDGE_NONE; |
180 | if ((dist = cursor->cursor->y - con->y) < closest_dist) { | 280 | if ((dist = cursor->cursor->y - con->pending.y) < closest_dist) { |
181 | closest_dist = dist; | 281 | closest_dist = dist; |
182 | e->target_edge = WLR_EDGE_TOP; | 282 | e->target_edge = WLR_EDGE_TOP; |
183 | } | 283 | } |
184 | if ((dist = cursor->cursor->x - con->x) < closest_dist) { | 284 | if ((dist = cursor->cursor->x - con->pending.x) < closest_dist) { |
185 | closest_dist = dist; | 285 | closest_dist = dist; |
186 | e->target_edge = WLR_EDGE_LEFT; | 286 | e->target_edge = WLR_EDGE_LEFT; |
187 | } | 287 | } |
188 | if ((dist = con->x + con->width - cursor->cursor->x) < closest_dist) { | 288 | if ((dist = con->pending.x + con->pending.width - cursor->cursor->x) < closest_dist) { |
189 | closest_dist = dist; | 289 | closest_dist = dist; |
190 | e->target_edge = WLR_EDGE_RIGHT; | 290 | e->target_edge = WLR_EDGE_RIGHT; |
191 | } | 291 | } |
192 | if ((dist = con->y + con->height - cursor->cursor->y) < closest_dist) { | 292 | if ((dist = con->pending.y + con->pending.height - cursor->cursor->y) < closest_dist) { |
193 | closest_dist = dist; | 293 | closest_dist = dist; |
194 | e->target_edge = WLR_EDGE_BOTTOM; | 294 | e->target_edge = WLR_EDGE_BOTTOM; |
195 | } | 295 | } |
@@ -199,10 +299,10 @@ static void handle_motion_postthreshold(struct sway_seat *seat) { | |||
199 | } | 299 | } |
200 | 300 | ||
201 | e->target_node = node; | 301 | e->target_node = node; |
202 | e->drop_box.x = con->content_x; | 302 | e->drop_box.x = con->pending.content_x; |
203 | e->drop_box.y = con->content_y; | 303 | e->drop_box.y = con->pending.content_y; |
204 | e->drop_box.width = con->content_width; | 304 | e->drop_box.width = con->pending.content_width; |
205 | e->drop_box.height = con->content_height; | 305 | e->drop_box.height = con->pending.content_height; |
206 | resize_box(&e->drop_box, e->target_edge, thickness); | 306 | resize_box(&e->drop_box, e->target_edge, thickness); |
207 | desktop_damage_box(&e->drop_box); | 307 | desktop_damage_box(&e->drop_box); |
208 | } | 308 | } |
@@ -214,6 +314,7 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) { | |||
214 | } else { | 314 | } else { |
215 | handle_motion_prethreshold(seat); | 315 | handle_motion_prethreshold(seat); |
216 | } | 316 | } |
317 | transaction_commit_dirty(); | ||
217 | } | 318 | } |
218 | 319 | ||
219 | static bool is_parallel(enum sway_container_layout layout, | 320 | static bool is_parallel(enum sway_container_layout layout, |
@@ -232,14 +333,15 @@ static void finalize_move(struct sway_seat *seat) { | |||
232 | } | 333 | } |
233 | 334 | ||
234 | struct sway_container *con = e->con; | 335 | struct sway_container *con = e->con; |
235 | struct sway_container *old_parent = con->parent; | 336 | struct sway_container *old_parent = con->pending.parent; |
236 | struct sway_workspace *old_ws = con->workspace; | 337 | struct sway_workspace *old_ws = con->pending.workspace; |
237 | struct sway_node *target_node = e->target_node; | 338 | struct sway_node *target_node = e->target_node; |
238 | struct sway_workspace *new_ws = target_node->type == N_WORKSPACE ? | 339 | struct sway_workspace *new_ws = target_node->type == N_WORKSPACE ? |
239 | target_node->sway_workspace : target_node->sway_container->workspace; | 340 | target_node->sway_workspace : target_node->sway_container->pending.workspace; |
240 | enum wlr_edges edge = e->target_edge; | 341 | enum wlr_edges edge = e->target_edge; |
241 | int after = edge != WLR_EDGE_TOP && edge != WLR_EDGE_LEFT; | 342 | int after = edge != WLR_EDGE_TOP && edge != WLR_EDGE_LEFT; |
242 | bool swap = edge == WLR_EDGE_NONE && target_node->type == N_CONTAINER; | 343 | bool swap = edge == WLR_EDGE_NONE && target_node->type == N_CONTAINER && |
344 | !e->split_target; | ||
243 | 345 | ||
244 | if (!swap) { | 346 | if (!swap) { |
245 | container_detach(con); | 347 | container_detach(con); |
@@ -248,6 +350,14 @@ static void finalize_move(struct sway_seat *seat) { | |||
248 | // Moving container into empty workspace | 350 | // Moving container into empty workspace |
249 | if (target_node->type == N_WORKSPACE && edge == WLR_EDGE_NONE) { | 351 | if (target_node->type == N_WORKSPACE && edge == WLR_EDGE_NONE) { |
250 | con = workspace_add_tiling(new_ws, con); | 352 | con = workspace_add_tiling(new_ws, con); |
353 | } else if (e->split_target) { | ||
354 | struct sway_container *target = target_node->sway_container; | ||
355 | enum sway_container_layout layout = container_parent_layout(target); | ||
356 | if (layout != L_TABBED && layout != L_STACKED) { | ||
357 | container_split(target, L_TABBED); | ||
358 | } | ||
359 | container_add_sibling(target, con, e->insert_after_target); | ||
360 | ipc_event_window(con, "move"); | ||
251 | } else if (target_node->type == N_CONTAINER) { | 361 | } else if (target_node->type == N_CONTAINER) { |
252 | // Moving container before/after another | 362 | // Moving container before/after another |
253 | struct sway_container *target = target_node->sway_container; | 363 | struct sway_container *target = target_node->sway_container; |
@@ -283,8 +393,8 @@ static void finalize_move(struct sway_seat *seat) { | |||
283 | int index = list_find(siblings, con); | 393 | int index = list_find(siblings, con); |
284 | struct sway_container *sibling = index == 0 ? | 394 | struct sway_container *sibling = index == 0 ? |
285 | siblings->items[1] : siblings->items[index - 1]; | 395 | siblings->items[1] : siblings->items[index - 1]; |
286 | con->width = sibling->width; | 396 | con->pending.width = sibling->pending.width; |
287 | con->height = sibling->height; | 397 | con->pending.height = sibling->pending.height; |
288 | con->width_fraction = sibling->width_fraction; | 398 | con->width_fraction = sibling->width_fraction; |
289 | con->height_fraction = sibling->height_fraction; | 399 | con->height_fraction = sibling->height_fraction; |
290 | } | 400 | } |
@@ -294,6 +404,7 @@ static void finalize_move(struct sway_seat *seat) { | |||
294 | arrange_workspace(new_ws); | 404 | arrange_workspace(new_ws); |
295 | } | 405 | } |
296 | 406 | ||
407 | transaction_commit_dirty(); | ||
297 | seatop_begin_default(seat); | 408 | seatop_begin_default(seat); |
298 | } | 409 | } |
299 | 410 | ||
@@ -348,6 +459,7 @@ void seatop_begin_move_tiling_threshold(struct sway_seat *seat, | |||
348 | seat->seatop_data = e; | 459 | seat->seatop_data = e; |
349 | 460 | ||
350 | container_raise_floating(con); | 461 | container_raise_floating(con); |
462 | transaction_commit_dirty(); | ||
351 | wlr_seat_pointer_notify_clear_focus(seat->wlr_seat); | 463 | wlr_seat_pointer_notify_clear_focus(seat->wlr_seat); |
352 | } | 464 | } |
353 | 465 | ||
diff --git a/sway/input/seatop_resize_floating.c b/sway/input/seatop_resize_floating.c index 5da22e47..8400a4b3 100644 --- a/sway/input/seatop_resize_floating.c +++ b/sway/input/seatop_resize_floating.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include <limits.h> | 2 | #include <limits.h> |
3 | #include <wlr/types/wlr_cursor.h> | 3 | #include <wlr/types/wlr_cursor.h> |
4 | #include <wlr/types/wlr_xcursor_manager.h> | 4 | #include <wlr/types/wlr_xcursor_manager.h> |
5 | #include "sway/desktop/transaction.h" | ||
5 | #include "sway/input/cursor.h" | 6 | #include "sway/input/cursor.h" |
6 | #include "sway/input/seat.h" | 7 | #include "sway/input/seat.h" |
7 | #include "sway/tree/arrange.h" | 8 | #include "sway/tree/arrange.h" |
@@ -27,6 +28,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
27 | if (seat->cursor->pressed_button_count == 0) { | 28 | if (seat->cursor->pressed_button_count == 0) { |
28 | container_set_resizing(con, false); | 29 | container_set_resizing(con, false); |
29 | arrange_container(con); // Send configure w/o resizing hint | 30 | arrange_container(con); // Send configure w/o resizing hint |
31 | transaction_commit_dirty(); | ||
30 | seatop_begin_default(seat); | 32 | seatop_begin_default(seat); |
31 | } | 33 | } |
32 | } | 34 | } |
@@ -116,23 +118,24 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) { | |||
116 | 118 | ||
117 | // Determine the amounts we need to bump everything relative to the current | 119 | // Determine the amounts we need to bump everything relative to the current |
118 | // size. | 120 | // size. |
119 | int relative_grow_width = width - con->width; | 121 | int relative_grow_width = width - con->pending.width; |
120 | int relative_grow_height = height - con->height; | 122 | int relative_grow_height = height - con->pending.height; |
121 | int relative_grow_x = (e->ref_con_lx + grow_x) - con->x; | 123 | int relative_grow_x = (e->ref_con_lx + grow_x) - con->pending.x; |
122 | int relative_grow_y = (e->ref_con_ly + grow_y) - con->y; | 124 | int relative_grow_y = (e->ref_con_ly + grow_y) - con->pending.y; |
123 | 125 | ||
124 | // Actually resize stuff | 126 | // Actually resize stuff |
125 | con->x += relative_grow_x; | 127 | con->pending.x += relative_grow_x; |
126 | con->y += relative_grow_y; | 128 | con->pending.y += relative_grow_y; |
127 | con->width += relative_grow_width; | 129 | con->pending.width += relative_grow_width; |
128 | con->height += relative_grow_height; | 130 | con->pending.height += relative_grow_height; |
129 | 131 | ||
130 | con->content_x += relative_grow_x; | 132 | con->pending.content_x += relative_grow_x; |
131 | con->content_y += relative_grow_y; | 133 | con->pending.content_y += relative_grow_y; |
132 | con->content_width += relative_grow_width; | 134 | con->pending.content_width += relative_grow_width; |
133 | con->content_height += relative_grow_height; | 135 | con->pending.content_height += relative_grow_height; |
134 | 136 | ||
135 | arrange_container(con); | 137 | arrange_container(con); |
138 | transaction_commit_dirty(); | ||
136 | } | 139 | } |
137 | 140 | ||
138 | static void handle_unref(struct sway_seat *seat, struct sway_container *con) { | 141 | static void handle_unref(struct sway_seat *seat, struct sway_container *con) { |
@@ -166,16 +169,17 @@ void seatop_begin_resize_floating(struct sway_seat *seat, | |||
166 | e->edge = edge == WLR_EDGE_NONE ? WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT : edge; | 169 | e->edge = edge == WLR_EDGE_NONE ? WLR_EDGE_BOTTOM | WLR_EDGE_RIGHT : edge; |
167 | e->ref_lx = seat->cursor->cursor->x; | 170 | e->ref_lx = seat->cursor->cursor->x; |
168 | e->ref_ly = seat->cursor->cursor->y; | 171 | e->ref_ly = seat->cursor->cursor->y; |
169 | e->ref_con_lx = con->x; | 172 | e->ref_con_lx = con->pending.x; |
170 | e->ref_con_ly = con->y; | 173 | e->ref_con_ly = con->pending.y; |
171 | e->ref_width = con->width; | 174 | e->ref_width = con->pending.width; |
172 | e->ref_height = con->height; | 175 | e->ref_height = con->pending.height; |
173 | 176 | ||
174 | seat->seatop_impl = &seatop_impl; | 177 | seat->seatop_impl = &seatop_impl; |
175 | seat->seatop_data = e; | 178 | seat->seatop_data = e; |
176 | 179 | ||
177 | container_set_resizing(con, true); | 180 | container_set_resizing(con, true); |
178 | container_raise_floating(con); | 181 | container_raise_floating(con); |
182 | transaction_commit_dirty(); | ||
179 | 183 | ||
180 | const char *image = edge == WLR_EDGE_NONE ? | 184 | const char *image = edge == WLR_EDGE_NONE ? |
181 | "se-resize" : wlr_xcursor_get_resize_name(edge); | 185 | "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 2cca805d..869d11b5 100644 --- a/sway/input/seatop_resize_tiling.c +++ b/sway/input/seatop_resize_tiling.c | |||
@@ -2,6 +2,7 @@ | |||
2 | #include <wlr/types/wlr_cursor.h> | 2 | #include <wlr/types/wlr_cursor.h> |
3 | #include <wlr/util/edges.h> | 3 | #include <wlr/util/edges.h> |
4 | #include "sway/commands.h" | 4 | #include "sway/commands.h" |
5 | #include "sway/desktop/transaction.h" | ||
5 | #include "sway/input/cursor.h" | 6 | #include "sway/input/cursor.h" |
6 | #include "sway/input/seat.h" | 7 | #include "sway/input/seat.h" |
7 | #include "sway/tree/arrange.h" | 8 | #include "sway/tree/arrange.h" |
@@ -52,21 +53,22 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec, | |||
52 | if (e->h_con) { | 53 | if (e->h_con) { |
53 | container_set_resizing(e->h_con, false); | 54 | container_set_resizing(e->h_con, false); |
54 | container_set_resizing(e->h_sib, false); | 55 | container_set_resizing(e->h_sib, false); |
55 | if (e->h_con->parent) { | 56 | if (e->h_con->pending.parent) { |
56 | arrange_container(e->h_con->parent); | 57 | arrange_container(e->h_con->pending.parent); |
57 | } else { | 58 | } else { |
58 | arrange_workspace(e->h_con->workspace); | 59 | arrange_workspace(e->h_con->pending.workspace); |
59 | } | 60 | } |
60 | } | 61 | } |
61 | if (e->v_con) { | 62 | if (e->v_con) { |
62 | container_set_resizing(e->v_con, false); | 63 | container_set_resizing(e->v_con, false); |
63 | container_set_resizing(e->v_sib, false); | 64 | container_set_resizing(e->v_sib, false); |
64 | if (e->v_con->parent) { | 65 | if (e->v_con->pending.parent) { |
65 | arrange_container(e->v_con->parent); | 66 | arrange_container(e->v_con->pending.parent); |
66 | } else { | 67 | } else { |
67 | arrange_workspace(e->v_con->workspace); | 68 | arrange_workspace(e->v_con->pending.workspace); |
68 | } | 69 | } |
69 | } | 70 | } |
71 | transaction_commit_dirty(); | ||
70 | seatop_begin_default(seat); | 72 | seatop_begin_default(seat); |
71 | } | 73 | } |
72 | } | 74 | } |
@@ -80,16 +82,16 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) { | |||
80 | 82 | ||
81 | if (e->h_con) { | 83 | if (e->h_con) { |
82 | if (e->edge & WLR_EDGE_LEFT) { | 84 | if (e->edge & WLR_EDGE_LEFT) { |
83 | amount_x = (e->h_con_orig_width - moved_x) - e->h_con->width; | 85 | amount_x = (e->h_con_orig_width - moved_x) - e->h_con->pending.width; |
84 | } else if (e->edge & WLR_EDGE_RIGHT) { | 86 | } else if (e->edge & WLR_EDGE_RIGHT) { |
85 | amount_x = (e->h_con_orig_width + moved_x) - e->h_con->width; | 87 | amount_x = (e->h_con_orig_width + moved_x) - e->h_con->pending.width; |
86 | } | 88 | } |
87 | } | 89 | } |
88 | if (e->v_con) { | 90 | if (e->v_con) { |
89 | if (e->edge & WLR_EDGE_TOP) { | 91 | if (e->edge & WLR_EDGE_TOP) { |
90 | amount_y = (e->v_con_orig_height - moved_y) - e->v_con->height; | 92 | amount_y = (e->v_con_orig_height - moved_y) - e->v_con->pending.height; |
91 | } else if (e->edge & WLR_EDGE_BOTTOM) { | 93 | } else if (e->edge & WLR_EDGE_BOTTOM) { |
92 | amount_y = (e->v_con_orig_height + moved_y) - e->v_con->height; | 94 | amount_y = (e->v_con_orig_height + moved_y) - e->v_con->pending.height; |
93 | } | 95 | } |
94 | } | 96 | } |
95 | 97 | ||
@@ -99,6 +101,7 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) { | |||
99 | if (amount_y != 0) { | 101 | if (amount_y != 0) { |
100 | container_resize_tiled(e->v_con, e->edge_y, amount_y); | 102 | container_resize_tiled(e->v_con, e->edge_y, amount_y); |
101 | } | 103 | } |
104 | transaction_commit_dirty(); | ||
102 | } | 105 | } |
103 | 106 | ||
104 | static void handle_unref(struct sway_seat *seat, struct sway_container *con) { | 107 | static void handle_unref(struct sway_seat *seat, struct sway_container *con) { |
@@ -140,7 +143,7 @@ void seatop_begin_resize_tiling(struct sway_seat *seat, | |||
140 | if (e->h_con) { | 143 | if (e->h_con) { |
141 | container_set_resizing(e->h_con, true); | 144 | container_set_resizing(e->h_con, true); |
142 | container_set_resizing(e->h_sib, true); | 145 | container_set_resizing(e->h_sib, true); |
143 | e->h_con_orig_width = e->h_con->width; | 146 | e->h_con_orig_width = e->h_con->pending.width; |
144 | } | 147 | } |
145 | } | 148 | } |
146 | if (edge & (WLR_EDGE_TOP | WLR_EDGE_BOTTOM)) { | 149 | if (edge & (WLR_EDGE_TOP | WLR_EDGE_BOTTOM)) { |
@@ -151,12 +154,13 @@ void seatop_begin_resize_tiling(struct sway_seat *seat, | |||
151 | if (e->v_con) { | 154 | if (e->v_con) { |
152 | container_set_resizing(e->v_con, true); | 155 | container_set_resizing(e->v_con, true); |
153 | container_set_resizing(e->v_sib, true); | 156 | container_set_resizing(e->v_sib, true); |
154 | e->v_con_orig_height = e->v_con->height; | 157 | e->v_con_orig_height = e->v_con->pending.height; |
155 | } | 158 | } |
156 | } | 159 | } |
157 | 160 | ||
158 | seat->seatop_impl = &seatop_impl; | 161 | seat->seatop_impl = &seatop_impl; |
159 | seat->seatop_data = e; | 162 | seat->seatop_data = e; |
160 | 163 | ||
164 | transaction_commit_dirty(); | ||
161 | wlr_seat_pointer_notify_clear_focus(seat->wlr_seat); | 165 | wlr_seat_pointer_notify_clear_focus(seat->wlr_seat); |
162 | } | 166 | } |
diff --git a/sway/input/switch.c b/sway/input/switch.c index b7c28df1..9ea87a1a 100644 --- a/sway/input/switch.c +++ b/sway/input/switch.c | |||
@@ -1,5 +1,4 @@ | |||
1 | #include "sway/config.h" | 1 | #include "sway/config.h" |
2 | #include "sway/desktop/transaction.h" | ||
3 | #include "sway/input/switch.h" | 2 | #include "sway/input/switch.h" |
4 | #include <wlr/types/wlr_idle.h> | 3 | #include <wlr/types/wlr_idle.h> |
5 | #include "log.h" | 4 | #include "log.h" |
@@ -61,9 +60,6 @@ static void execute_binding(struct sway_switch *sway_switch) { | |||
61 | seat_execute_command(seat, dummy_binding); | 60 | seat_execute_command(seat, dummy_binding); |
62 | free(dummy_binding); | 61 | free(dummy_binding); |
63 | } | 62 | } |
64 | |||
65 | transaction_commit_dirty(); | ||
66 | |||
67 | } | 63 | } |
68 | 64 | ||
69 | static void handle_switch_toggle(struct wl_listener *listener, void *data) { | 65 | static void handle_switch_toggle(struct wl_listener *listener, void *data) { |
diff --git a/sway/input/text_input.c b/sway/input/text_input.c index f83726ee..b8c19c17 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) { | |||
55 | wlr_text_input_v3_send_done(text_input->input); | 55 | wlr_text_input_v3_send_done(text_input->input); |
56 | } | 56 | } |
57 | 57 | ||
58 | static void handle_im_keyboard_grab_destroy(struct wl_listener *listener, void *data) { | ||
59 | struct sway_input_method_relay *relay = wl_container_of(listener, relay, | ||
60 | input_method_keyboard_grab_destroy); | ||
61 | struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data; | ||
62 | wl_list_remove(&relay->input_method_keyboard_grab_destroy.link); | ||
63 | |||
64 | if (keyboard_grab->keyboard) { | ||
65 | // send modifier state to original client | ||
66 | wlr_seat_keyboard_notify_modifiers(keyboard_grab->input_method->seat, | ||
67 | &keyboard_grab->keyboard->modifiers); | ||
68 | } | ||
69 | } | ||
70 | |||
71 | static void handle_im_grab_keyboard(struct wl_listener *listener, void *data) { | ||
72 | struct sway_input_method_relay *relay = wl_container_of(listener, relay, | ||
73 | input_method_grab_keyboard); | ||
74 | struct wlr_input_method_keyboard_grab_v2 *keyboard_grab = data; | ||
75 | |||
76 | // send modifier state to grab | ||
77 | struct wlr_keyboard *active_keyboard = wlr_seat_get_keyboard(relay->seat->wlr_seat); | ||
78 | wlr_input_method_keyboard_grab_v2_set_keyboard(keyboard_grab, | ||
79 | active_keyboard); | ||
80 | wlr_input_method_keyboard_grab_v2_send_modifiers(keyboard_grab, | ||
81 | &active_keyboard->modifiers); | ||
82 | |||
83 | wl_signal_add(&keyboard_grab->events.destroy, | ||
84 | &relay->input_method_keyboard_grab_destroy); | ||
85 | relay->input_method_keyboard_grab_destroy.notify = | ||
86 | handle_im_keyboard_grab_destroy; | ||
87 | } | ||
88 | |||
58 | static void text_input_set_pending_focused_surface( | 89 | static void text_input_set_pending_focused_surface( |
59 | struct sway_text_input *text_input, struct wlr_surface *surface) { | 90 | struct sway_text_input *text_input, struct wlr_surface *surface) { |
60 | wl_list_remove(&text_input->pending_focused_surface_destroy.link); | 91 | 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, | |||
92 | return; | 123 | return; |
93 | } | 124 | } |
94 | // TODO: only send each of those if they were modified | 125 | // TODO: only send each of those if they were modified |
95 | wlr_input_method_v2_send_surrounding_text(input_method, | 126 | if (input->active_features & WLR_TEXT_INPUT_V3_FEATURE_SURROUNDING_TEXT) { |
96 | input->current.surrounding.text, input->current.surrounding.cursor, | 127 | wlr_input_method_v2_send_surrounding_text(input_method, |
97 | input->current.surrounding.anchor); | 128 | input->current.surrounding.text, input->current.surrounding.cursor, |
129 | input->current.surrounding.anchor); | ||
130 | } | ||
98 | wlr_input_method_v2_send_text_change_cause(input_method, | 131 | wlr_input_method_v2_send_text_change_cause(input_method, |
99 | input->current.text_change_cause); | 132 | input->current.text_change_cause); |
100 | wlr_input_method_v2_send_content_type(input_method, | 133 | if (input->active_features & WLR_TEXT_INPUT_V3_FEATURE_CONTENT_TYPE) { |
101 | input->current.content_type.hint, input->current.content_type.purpose); | 134 | wlr_input_method_v2_send_content_type(input_method, |
135 | input->current.content_type.hint, | ||
136 | input->current.content_type.purpose); | ||
137 | } | ||
102 | wlr_input_method_v2_send_done(input_method); | 138 | wlr_input_method_v2_send_done(input_method); |
103 | // TODO: pass intent, display popup size | 139 | // TODO: pass intent, display popup size |
104 | } | 140 | } |
@@ -144,6 +180,10 @@ static void handle_text_input_disable(struct wl_listener *listener, | |||
144 | void *data) { | 180 | void *data) { |
145 | struct sway_text_input *text_input = wl_container_of(listener, text_input, | 181 | struct sway_text_input *text_input = wl_container_of(listener, text_input, |
146 | text_input_disable); | 182 | text_input_disable); |
183 | if (text_input->input->focused_surface == NULL) { | ||
184 | sway_log(SWAY_DEBUG, "Disabling text input, but no longer focused"); | ||
185 | return; | ||
186 | } | ||
147 | relay_disable_text_input(text_input->relay, text_input); | 187 | relay_disable_text_input(text_input->relay, text_input); |
148 | } | 188 | } |
149 | 189 | ||
@@ -236,6 +276,9 @@ static void relay_handle_input_method(struct wl_listener *listener, | |||
236 | wl_signal_add(&relay->input_method->events.commit, | 276 | wl_signal_add(&relay->input_method->events.commit, |
237 | &relay->input_method_commit); | 277 | &relay->input_method_commit); |
238 | relay->input_method_commit.notify = handle_im_commit; | 278 | relay->input_method_commit.notify = handle_im_commit; |
279 | wl_signal_add(&relay->input_method->events.grab_keyboard, | ||
280 | &relay->input_method_grab_keyboard); | ||
281 | relay->input_method_grab_keyboard.notify = handle_im_grab_keyboard; | ||
239 | wl_signal_add(&relay->input_method->events.destroy, | 282 | wl_signal_add(&relay->input_method->events.destroy, |
240 | &relay->input_method_destroy); | 283 | &relay->input_method_destroy); |
241 | relay->input_method_destroy.notify = handle_im_destroy; | 284 | relay->input_method_destroy.notify = handle_im_destroy; |
diff --git a/sway/ipc-json.c b/sway/ipc-json.c index fceee84d..1b64f86e 100644 --- a/sway/ipc-json.c +++ b/sway/ipc-json.c | |||
@@ -1,7 +1,11 @@ | |||
1 | #include <ctype.h> | ||
2 | #include <float.h> | ||
1 | #include <json.h> | 3 | #include <json.h> |
2 | #include <libevdev/libevdev.h> | 4 | #include <libevdev/libevdev.h> |
3 | #include <stdio.h> | 5 | #include <stdio.h> |
4 | #include <ctype.h> | 6 | #include <wlr/backend/libinput.h> |
7 | #include <wlr/types/wlr_output.h> | ||
8 | #include <xkbcommon/xkbcommon.h> | ||
5 | #include "config.h" | 9 | #include "config.h" |
6 | #include "log.h" | 10 | #include "log.h" |
7 | #include "sway/config.h" | 11 | #include "sway/config.h" |
@@ -13,16 +17,26 @@ | |||
13 | #include "sway/input/input-manager.h" | 17 | #include "sway/input/input-manager.h" |
14 | #include "sway/input/cursor.h" | 18 | #include "sway/input/cursor.h" |
15 | #include "sway/input/seat.h" | 19 | #include "sway/input/seat.h" |
16 | #include <wlr/backend/libinput.h> | ||
17 | #include <wlr/types/wlr_box.h> | ||
18 | #include <wlr/types/wlr_output.h> | ||
19 | #include <xkbcommon/xkbcommon.h> | ||
20 | #include "wlr-layer-shell-unstable-v1-protocol.h" | 20 | #include "wlr-layer-shell-unstable-v1-protocol.h" |
21 | #include "sway/desktop/idle_inhibit_v1.h" | 21 | #include "sway/desktop/idle_inhibit_v1.h" |
22 | 22 | ||
23 | static const int i3_output_id = INT32_MAX; | 23 | static const int i3_output_id = INT32_MAX; |
24 | static const int i3_scratch_id = INT32_MAX - 1; | 24 | static const int i3_scratch_id = INT32_MAX - 1; |
25 | 25 | ||
26 | static const char *ipc_json_node_type_description(enum sway_node_type node_type) { | ||
27 | switch (node_type) { | ||
28 | case N_ROOT: | ||
29 | return "root"; | ||
30 | case N_OUTPUT: | ||
31 | return "output"; | ||
32 | case N_WORKSPACE: | ||
33 | return "workspace"; | ||
34 | case N_CONTAINER: | ||
35 | return "con"; | ||
36 | } | ||
37 | return "none"; | ||
38 | } | ||
39 | |||
26 | static const char *ipc_json_layout_description(enum sway_container_layout l) { | 40 | static const char *ipc_json_layout_description(enum sway_container_layout l) { |
27 | switch (l) { | 41 | switch (l) { |
28 | case L_VERT: | 42 | case L_VERT: |
@@ -189,16 +203,22 @@ static json_object *ipc_json_create_empty_rect(void) { | |||
189 | return ipc_json_create_rect(&empty); | 203 | return ipc_json_create_rect(&empty); |
190 | } | 204 | } |
191 | 205 | ||
192 | static json_object *ipc_json_create_node(int id, char *name, | 206 | static json_object *ipc_json_create_node(int id, const char* type, char *name, |
193 | bool focused, json_object *focus, struct wlr_box *box) { | 207 | bool focused, json_object *focus, struct wlr_box *box) { |
194 | json_object *object = json_object_new_object(); | 208 | json_object *object = json_object_new_object(); |
195 | 209 | ||
196 | json_object_object_add(object, "id", json_object_new_int(id)); | 210 | json_object_object_add(object, "id", json_object_new_int(id)); |
197 | json_object_object_add(object, "name", | 211 | json_object_object_add(object, "type", json_object_new_string(type)); |
198 | name ? json_object_new_string(name) : NULL); | 212 | json_object_object_add(object, "orientation", |
199 | json_object_object_add(object, "rect", ipc_json_create_rect(box)); | 213 | json_object_new_string( |
214 | ipc_json_orientation_description(L_HORIZ))); | ||
215 | json_object_object_add(object, "percent", NULL); | ||
216 | json_object_object_add(object, "urgent", json_object_new_boolean(false)); | ||
217 | json_object_object_add(object, "marks", json_object_new_array()); | ||
200 | json_object_object_add(object, "focused", json_object_new_boolean(focused)); | 218 | json_object_object_add(object, "focused", json_object_new_boolean(focused)); |
201 | json_object_object_add(object, "focus", focus); | 219 | json_object_object_add(object, "layout", |
220 | json_object_new_string( | ||
221 | ipc_json_layout_description(L_HORIZ))); | ||
202 | 222 | ||
203 | // set default values to be compatible with i3 | 223 | // set default values to be compatible with i3 |
204 | json_object_object_add(object, "border", | 224 | json_object_object_add(object, "border", |
@@ -206,35 +226,25 @@ static json_object *ipc_json_create_node(int id, char *name, | |||
206 | ipc_json_border_description(B_NONE))); | 226 | ipc_json_border_description(B_NONE))); |
207 | json_object_object_add(object, "current_border_width", | 227 | json_object_object_add(object, "current_border_width", |
208 | json_object_new_int(0)); | 228 | json_object_new_int(0)); |
209 | json_object_object_add(object, "layout", | 229 | json_object_object_add(object, "rect", ipc_json_create_rect(box)); |
210 | json_object_new_string( | ||
211 | ipc_json_layout_description(L_HORIZ))); | ||
212 | json_object_object_add(object, "orientation", | ||
213 | json_object_new_string( | ||
214 | ipc_json_orientation_description(L_HORIZ))); | ||
215 | json_object_object_add(object, "percent", NULL); | ||
216 | json_object_object_add(object, "window_rect", ipc_json_create_empty_rect()); | ||
217 | json_object_object_add(object, "deco_rect", ipc_json_create_empty_rect()); | 230 | json_object_object_add(object, "deco_rect", ipc_json_create_empty_rect()); |
231 | json_object_object_add(object, "window_rect", ipc_json_create_empty_rect()); | ||
218 | json_object_object_add(object, "geometry", ipc_json_create_empty_rect()); | 232 | json_object_object_add(object, "geometry", ipc_json_create_empty_rect()); |
233 | json_object_object_add(object, "name", | ||
234 | name ? json_object_new_string(name) : NULL); | ||
219 | json_object_object_add(object, "window", NULL); | 235 | json_object_object_add(object, "window", NULL); |
220 | json_object_object_add(object, "urgent", json_object_new_boolean(false)); | ||
221 | json_object_object_add(object, "marks", json_object_new_array()); | ||
222 | json_object_object_add(object, "fullscreen_mode", json_object_new_int(0)); | ||
223 | json_object_object_add(object, "nodes", json_object_new_array()); | 236 | json_object_object_add(object, "nodes", json_object_new_array()); |
224 | json_object_object_add(object, "floating_nodes", json_object_new_array()); | 237 | json_object_object_add(object, "floating_nodes", json_object_new_array()); |
238 | json_object_object_add(object, "focus", focus); | ||
239 | json_object_object_add(object, "fullscreen_mode", json_object_new_int(0)); | ||
225 | json_object_object_add(object, "sticky", json_object_new_boolean(false)); | 240 | json_object_object_add(object, "sticky", json_object_new_boolean(false)); |
226 | 241 | ||
227 | return object; | 242 | return object; |
228 | } | 243 | } |
229 | 244 | ||
230 | static void ipc_json_describe_root(struct sway_root *root, json_object *object) { | ||
231 | json_object_object_add(object, "type", json_object_new_string("root")); | ||
232 | } | ||
233 | |||
234 | static void ipc_json_describe_output(struct sway_output *output, | 245 | static void ipc_json_describe_output(struct sway_output *output, |
235 | json_object *object) { | 246 | json_object *object) { |
236 | struct wlr_output *wlr_output = output->wlr_output; | 247 | struct wlr_output *wlr_output = output->wlr_output; |
237 | json_object_object_add(object, "type", json_object_new_string("output")); | ||
238 | json_object_object_add(object, "active", json_object_new_boolean(true)); | 248 | json_object_object_add(object, "active", json_object_new_boolean(true)); |
239 | json_object_object_add(object, "dpms", | 249 | json_object_object_add(object, "dpms", |
240 | json_object_new_boolean(wlr_output->enabled)); | 250 | json_object_new_boolean(wlr_output->enabled)); |
@@ -369,11 +379,9 @@ static json_object *ipc_json_describe_scratchpad_output(void) { | |||
369 | json_object_new_int(container->node.id)); | 379 | json_object_new_int(container->node.id)); |
370 | } | 380 | } |
371 | 381 | ||
372 | json_object *workspace = ipc_json_create_node(i3_scratch_id, | 382 | json_object *workspace = ipc_json_create_node(i3_scratch_id, "workspace", |
373 | "__i3_scratch", false, workspace_focus, &box); | 383 | "__i3_scratch", false, workspace_focus, &box); |
374 | json_object_object_add(workspace, "fullscreen_mode", json_object_new_int(1)); | 384 | json_object_object_add(workspace, "fullscreen_mode", json_object_new_int(1)); |
375 | json_object_object_add(workspace, "type", | ||
376 | json_object_new_string("workspace")); | ||
377 | 385 | ||
378 | // List all hidden scratchpad containers as floating nodes | 386 | // List all hidden scratchpad containers as floating nodes |
379 | json_object *floating_array = json_object_new_array(); | 387 | json_object *floating_array = json_object_new_array(); |
@@ -390,10 +398,8 @@ static json_object *ipc_json_describe_scratchpad_output(void) { | |||
390 | json_object *output_focus = json_object_new_array(); | 398 | json_object *output_focus = json_object_new_array(); |
391 | json_object_array_add(output_focus, json_object_new_int(i3_scratch_id)); | 399 | json_object_array_add(output_focus, json_object_new_int(i3_scratch_id)); |
392 | 400 | ||
393 | json_object *output = ipc_json_create_node(i3_output_id, | 401 | json_object *output = ipc_json_create_node(i3_output_id, "output", |
394 | "__i3", false, output_focus, &box); | 402 | "__i3", false, output_focus, &box); |
395 | json_object_object_add(output, "type", | ||
396 | json_object_new_string("output")); | ||
397 | json_object_object_add(output, "layout", | 403 | json_object_object_add(output, "layout", |
398 | json_object_new_string("output")); | 404 | json_object_new_string("output")); |
399 | 405 | ||
@@ -423,7 +429,6 @@ static void ipc_json_describe_workspace(struct sway_workspace *workspace, | |||
423 | json_object_object_add(object, "fullscreen_mode", json_object_new_int(1)); | 429 | json_object_object_add(object, "fullscreen_mode", json_object_new_int(1)); |
424 | json_object_object_add(object, "output", workspace->output ? | 430 | json_object_object_add(object, "output", workspace->output ? |
425 | json_object_new_string(workspace->output->wlr_output->name) : NULL); | 431 | json_object_new_string(workspace->output->wlr_output->name) : NULL); |
426 | json_object_object_add(object, "type", json_object_new_string("workspace")); | ||
427 | json_object_object_add(object, "urgent", | 432 | json_object_object_add(object, "urgent", |
428 | json_object_new_boolean(workspace->urgent)); | 433 | json_object_new_boolean(workspace->urgent)); |
429 | json_object_object_add(object, "representation", workspace->representation ? | 434 | 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) { | |||
451 | bool tab_or_stack = parent_layout == L_TABBED || parent_layout == L_STACKED; | 456 | bool tab_or_stack = parent_layout == L_TABBED || parent_layout == L_STACKED; |
452 | if (((!tab_or_stack || container_is_floating(c)) && | 457 | if (((!tab_or_stack || container_is_floating(c)) && |
453 | c->current.border != B_NORMAL) || | 458 | c->current.border != B_NORMAL) || |
454 | c->fullscreen_mode != FULLSCREEN_NONE || | 459 | c->pending.fullscreen_mode != FULLSCREEN_NONE || |
455 | c->workspace == NULL) { | 460 | c->pending.workspace == NULL) { |
456 | deco_rect->x = deco_rect->y = deco_rect->width = deco_rect->height = 0; | 461 | deco_rect->x = deco_rect->y = deco_rect->width = deco_rect->height = 0; |
457 | return; | 462 | return; |
458 | } | 463 | } |
459 | 464 | ||
460 | if (c->parent) { | 465 | if (c->pending.parent) { |
461 | deco_rect->x = c->x - c->parent->x; | 466 | deco_rect->x = c->pending.x - c->pending.parent->pending.x; |
462 | deco_rect->y = c->y - c->parent->y; | 467 | deco_rect->y = c->pending.y - c->pending.parent->pending.y; |
463 | } else { | 468 | } else { |
464 | deco_rect->x = c->x - c->workspace->x; | 469 | deco_rect->x = c->pending.x - c->pending.workspace->x; |
465 | deco_rect->y = c->y - c->workspace->y; | 470 | deco_rect->y = c->pending.y - c->pending.workspace->y; |
466 | } | 471 | } |
467 | deco_rect->width = c->width; | 472 | deco_rect->width = c->pending.width; |
468 | deco_rect->height = container_titlebar_height(); | 473 | deco_rect->height = container_titlebar_height(); |
469 | 474 | ||
470 | if (!container_is_floating(c)) { | 475 | if (!container_is_floating(c)) { |
471 | if (parent_layout == L_TABBED) { | 476 | if (parent_layout == L_TABBED) { |
472 | deco_rect->width = c->parent | 477 | deco_rect->width = c->pending.parent |
473 | ? c->parent->width / c->parent->children->length | 478 | ? c->pending.parent->pending.width / c->pending.parent->pending.children->length |
474 | : c->workspace->width / c->workspace->tiling->length; | 479 | : c->pending.workspace->width / c->pending.workspace->tiling->length; |
475 | deco_rect->x += deco_rect->width * container_sibling_index(c); | 480 | deco_rect->x += deco_rect->width * container_sibling_index(c); |
476 | } else if (parent_layout == L_STACKED) { | 481 | } else if (parent_layout == L_STACKED) { |
477 | if (!c->view) { | 482 | if (!c->view) { |
@@ -494,10 +499,10 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object | |||
494 | json_object_object_add(object, "visible", json_object_new_boolean(visible)); | 499 | json_object_object_add(object, "visible", json_object_new_boolean(visible)); |
495 | 500 | ||
496 | struct wlr_box window_box = { | 501 | struct wlr_box window_box = { |
497 | c->content_x - c->x, | 502 | c->pending.content_x - c->pending.x, |
498 | (c->current.border == B_PIXEL) ? c->current.border_thickness : 0, | 503 | (c->current.border == B_PIXEL) ? c->current.border_thickness : 0, |
499 | c->content_width, | 504 | c->pending.content_width, |
500 | c->content_height | 505 | c->pending.content_height |
501 | }; | 506 | }; |
502 | 507 | ||
503 | json_object_object_add(object, "window_rect", ipc_json_create_rect(&window_box)); | 508 | 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 | |||
583 | static void ipc_json_describe_container(struct sway_container *c, json_object *object) { | 588 | static void ipc_json_describe_container(struct sway_container *c, json_object *object) { |
584 | json_object_object_add(object, "name", | 589 | json_object_object_add(object, "name", |
585 | c->title ? json_object_new_string(c->title) : NULL); | 590 | c->title ? json_object_new_string(c->title) : NULL); |
586 | json_object_object_add(object, "type", | 591 | if (container_is_floating(c)) { |
587 | json_object_new_string(container_is_floating(c) ? "floating_con" : "con")); | 592 | json_object_object_add(object, "type", |
593 | json_object_new_string("floating_con")); | ||
594 | } | ||
588 | 595 | ||
589 | json_object_object_add(object, "layout", | 596 | json_object_object_add(object, "layout", |
590 | json_object_new_string( | 597 | json_object_new_string( |
591 | ipc_json_layout_description(c->layout))); | 598 | ipc_json_layout_description(c->pending.layout))); |
592 | 599 | ||
593 | json_object_object_add(object, "orientation", | 600 | json_object_object_add(object, "orientation", |
594 | json_object_new_string( | 601 | json_object_new_string( |
595 | ipc_json_orientation_description(c->layout))); | 602 | ipc_json_orientation_description(c->pending.layout))); |
596 | 603 | ||
597 | bool urgent = c->view ? | 604 | bool urgent = c->view ? |
598 | view_is_urgent(c->view) : container_has_urgent_child(c); | 605 | 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 | |||
600 | json_object_object_add(object, "sticky", json_object_new_boolean(c->is_sticky)); | 607 | json_object_object_add(object, "sticky", json_object_new_boolean(c->is_sticky)); |
601 | 608 | ||
602 | json_object_object_add(object, "fullscreen_mode", | 609 | json_object_object_add(object, "fullscreen_mode", |
603 | json_object_new_int(c->fullscreen_mode)); | 610 | json_object_new_int(c->pending.fullscreen_mode)); |
604 | 611 | ||
605 | struct sway_node *parent = node_get_parent(&c->node); | 612 | struct sway_node *parent = node_get_parent(&c->node); |
606 | struct wlr_box parent_box = {0, 0, 0, 0}; | 613 | 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 | |||
610 | } | 617 | } |
611 | 618 | ||
612 | if (parent_box.width != 0 && parent_box.height != 0) { | 619 | if (parent_box.width != 0 && parent_box.height != 0) { |
613 | double percent = ((double)c->width / parent_box.width) | 620 | double percent = ((double)c->pending.width / parent_box.width) |
614 | * ((double)c->height / parent_box.height); | 621 | * ((double)c->pending.height / parent_box.height); |
615 | json_object_object_add(object, "percent", json_object_new_double(percent)); | 622 | json_object_object_add(object, "percent", json_object_new_double(percent)); |
616 | } | 623 | } |
617 | 624 | ||
@@ -692,12 +699,11 @@ json_object *ipc_json_describe_node(struct sway_node *node) { | |||
692 | }; | 699 | }; |
693 | seat_for_each_node(seat, focus_inactive_children_iterator, &data); | 700 | seat_for_each_node(seat, focus_inactive_children_iterator, &data); |
694 | 701 | ||
695 | json_object *object = ipc_json_create_node( | 702 | json_object *object = ipc_json_create_node((int)node->id, |
696 | (int)node->id, name, focused, focus, &box); | 703 | ipc_json_node_type_description(node->type), name, focused, focus, &box); |
697 | 704 | ||
698 | switch (node->type) { | 705 | switch (node->type) { |
699 | case N_ROOT: | 706 | case N_ROOT: |
700 | ipc_json_describe_root(root, object); | ||
701 | break; | 707 | break; |
702 | case N_OUTPUT: | 708 | case N_OUTPUT: |
703 | ipc_json_describe_output(node->sway_output, object); | 709 | ipc_json_describe_output(node->sway_output, object); |
@@ -743,10 +749,10 @@ json_object *ipc_json_describe_node_recursive(struct sway_node *node) { | |||
743 | } | 749 | } |
744 | break; | 750 | break; |
745 | case N_CONTAINER: | 751 | case N_CONTAINER: |
746 | if (node->sway_container->children) { | 752 | if (node->sway_container->pending.children) { |
747 | for (i = 0; i < node->sway_container->children->length; ++i) { | 753 | for (i = 0; i < node->sway_container->pending.children->length; ++i) { |
748 | struct sway_container *child = | 754 | struct sway_container *child = |
749 | node->sway_container->children->items[i]; | 755 | node->sway_container->pending.children->items[i]; |
750 | json_object_array_add(children, | 756 | json_object_array_add(children, |
751 | ipc_json_describe_node_recursive(&child->node)); | 757 | ipc_json_describe_node_recursive(&child->node)); |
752 | } | 758 | } |
@@ -996,6 +1002,17 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) { | |||
996 | } | 1002 | } |
997 | } | 1003 | } |
998 | 1004 | ||
1005 | if (device->wlr_device->type == WLR_INPUT_DEVICE_POINTER) { | ||
1006 | struct input_config *ic = input_device_get_config(device); | ||
1007 | float scroll_factor = 1.0f; | ||
1008 | if (ic != NULL && !isnan(ic->scroll_factor) && | ||
1009 | ic->scroll_factor != FLT_MIN) { | ||
1010 | scroll_factor = ic->scroll_factor; | ||
1011 | } | ||
1012 | json_object_object_add(object, "scroll_factor", | ||
1013 | json_object_new_double(scroll_factor)); | ||
1014 | } | ||
1015 | |||
999 | if (wlr_input_device_is_libinput(device->wlr_device)) { | 1016 | if (wlr_input_device_is_libinput(device->wlr_device)) { |
1000 | struct libinput_device *libinput_dev; | 1017 | struct libinput_device *libinput_dev; |
1001 | libinput_dev = wlr_libinput_get_device_handle(device->wlr_device); | 1018 | libinput_dev = wlr_libinput_get_device_handle(device->wlr_device); |
@@ -1109,7 +1126,9 @@ json_object *ipc_json_describe_bar_config(struct bar_config *bar) { | |||
1109 | json_object_object_add(json, "verbose", | 1126 | json_object_object_add(json, "verbose", |
1110 | json_object_new_boolean(bar->verbose)); | 1127 | json_object_new_boolean(bar->verbose)); |
1111 | json_object_object_add(json, "pango_markup", | 1128 | json_object_object_add(json, "pango_markup", |
1112 | json_object_new_boolean(bar->pango_markup)); | 1129 | json_object_new_boolean(bar->pango_markup == PANGO_MARKUP_DEFAULT |
1130 | ? config->pango_markup | ||
1131 | : bar->pango_markup)); | ||
1113 | 1132 | ||
1114 | json_object *colors = json_object_new_object(); | 1133 | json_object *colors = json_object_new_object(); |
1115 | json_object_object_add(colors, "background", | 1134 | json_object_object_add(colors, "background", |
diff --git a/sway/main.c b/sway/main.c index 0c219fb3..e960c4e2 100644 --- a/sway/main.c +++ b/sway/main.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <sys/un.h> | 12 | #include <sys/un.h> |
13 | #include <unistd.h> | 13 | #include <unistd.h> |
14 | #include <wlr/util/log.h> | 14 | #include <wlr/util/log.h> |
15 | #include <wlr/version.h> | ||
15 | #include "sway/commands.h" | 16 | #include "sway/commands.h" |
16 | #include "sway/config.h" | 17 | #include "sway/config.h" |
17 | #include "sway/server.h" | 18 | #include "sway/server.h" |
@@ -46,43 +47,6 @@ void sig_handler(int signal) { | |||
46 | sway_terminate(EXIT_SUCCESS); | 47 | sway_terminate(EXIT_SUCCESS); |
47 | } | 48 | } |
48 | 49 | ||
49 | void detect_raspi(void) { | ||
50 | bool raspi = false; | ||
51 | FILE *f = fopen("/sys/firmware/devicetree/base/model", "r"); | ||
52 | if (!f) { | ||
53 | return; | ||
54 | } | ||
55 | char *line = NULL; | ||
56 | size_t line_size = 0; | ||
57 | while (getline(&line, &line_size, f) != -1) { | ||
58 | if (strstr(line, "Raspberry Pi")) { | ||
59 | raspi = true; | ||
60 | break; | ||
61 | } | ||
62 | } | ||
63 | fclose(f); | ||
64 | FILE *g = fopen("/proc/modules", "r"); | ||
65 | if (!g) { | ||
66 | free(line); | ||
67 | return; | ||
68 | } | ||
69 | bool vc4 = false; | ||
70 | while (getline(&line, &line_size, g) != -1) { | ||
71 | if (strstr(line, "vc4")) { | ||
72 | vc4 = true; | ||
73 | break; | ||
74 | } | ||
75 | } | ||
76 | free(line); | ||
77 | fclose(g); | ||
78 | if (!vc4 && raspi) { | ||
79 | fprintf(stderr, "\x1B[1;31mWarning: You have a " | ||
80 | "Raspberry Pi, but the vc4 Module is " | ||
81 | "not loaded! Set 'dtoverlay=vc4-kms-v3d'" | ||
82 | "in /boot/config.txt and reboot.\x1B[0m\n"); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | void detect_proprietary(int allow_unsupported_gpu) { | 50 | void detect_proprietary(int allow_unsupported_gpu) { |
87 | FILE *f = fopen("/proc/modules", "r"); | 51 | FILE *f = fopen("/proc/modules", "r"); |
88 | if (!f) { | 52 | if (!f) { |
@@ -218,6 +182,8 @@ void enable_debug_flag(const char *flag) { | |||
218 | debug.txn_timings = true; | 182 | debug.txn_timings = true; |
219 | } else if (strncmp(flag, "txn-timeout=", 12) == 0) { | 183 | } else if (strncmp(flag, "txn-timeout=", 12) == 0) { |
220 | server.txn_timeout_ms = atoi(&flag[12]); | 184 | server.txn_timeout_ms = atoi(&flag[12]); |
185 | } else if (strcmp(flag, "noscanout") == 0) { | ||
186 | debug.noscanout = true; | ||
221 | } else { | 187 | } else { |
222 | sway_log(SWAY_ERROR, "Unknown debug flag: %s", flag); | 188 | sway_log(SWAY_ERROR, "Unknown debug flag: %s", flag); |
223 | } | 189 | } |
@@ -245,7 +211,7 @@ static void handle_wlr_log(enum wlr_log_importance importance, | |||
245 | int main(int argc, char **argv) { | 211 | int main(int argc, char **argv) { |
246 | static int verbose = 0, debug = 0, validate = 0, allow_unsupported_gpu = 0; | 212 | static int verbose = 0, debug = 0, validate = 0, allow_unsupported_gpu = 0; |
247 | 213 | ||
248 | static struct option long_options[] = { | 214 | static const struct option long_options[] = { |
249 | {"help", no_argument, NULL, 'h'}, | 215 | {"help", no_argument, NULL, 'h'}, |
250 | {"config", required_argument, NULL, 'c'}, | 216 | {"config", required_argument, NULL, 'c'}, |
251 | {"validate", no_argument, NULL, 'C'}, | 217 | {"validate", no_argument, NULL, 'C'}, |
@@ -344,11 +310,11 @@ int main(int argc, char **argv) { | |||
344 | } | 310 | } |
345 | 311 | ||
346 | sway_log(SWAY_INFO, "Sway version " SWAY_VERSION); | 312 | sway_log(SWAY_INFO, "Sway version " SWAY_VERSION); |
313 | sway_log(SWAY_INFO, "wlroots version " WLR_VERSION_STR); | ||
347 | log_kernel(); | 314 | log_kernel(); |
348 | log_distro(); | 315 | log_distro(); |
349 | log_env(); | 316 | log_env(); |
350 | detect_proprietary(allow_unsupported_gpu); | 317 | detect_proprietary(allow_unsupported_gpu); |
351 | detect_raspi(); | ||
352 | 318 | ||
353 | if (optind < argc) { // Behave as IPC client | 319 | if (optind < argc) { // Behave as IPC client |
354 | if (optind != 1) { | 320 | if (optind != 1) { |
diff --git a/sway/meson.build b/sway/meson.build index 6e138101..1402db15 100644 --- a/sway/meson.build +++ b/sway/meson.build | |||
@@ -8,6 +8,7 @@ sway_sources = files( | |||
8 | 'main.c', | 8 | 'main.c', |
9 | 'server.c', | 9 | 'server.c', |
10 | 'swaynag.c', | 10 | 'swaynag.c', |
11 | 'xdg_activation_v1.c', | ||
11 | 'xdg_decoration.c', | 12 | 'xdg_decoration.c', |
12 | 13 | ||
13 | 'desktop/desktop.c', | 14 | 'desktop/desktop.c', |
@@ -204,9 +205,11 @@ sway_sources = files( | |||
204 | 205 | ||
205 | sway_deps = [ | 206 | sway_deps = [ |
206 | cairo, | 207 | cairo, |
208 | drm, | ||
207 | jsonc, | 209 | jsonc, |
208 | libevdev, | 210 | libevdev, |
209 | libinput, | 211 | libinput, |
212 | libudev, | ||
210 | math, | 213 | math, |
211 | pango, | 214 | pango, |
212 | pcre, | 215 | pcre, |
diff --git a/sway/server.c b/sway/server.c index f51fcfe2..b187fcd5 100644 --- a/sway/server.c +++ b/sway/server.c | |||
@@ -9,9 +9,11 @@ | |||
9 | #include <wlr/backend/multi.h> | 9 | #include <wlr/backend/multi.h> |
10 | #include <wlr/backend/noop.h> | 10 | #include <wlr/backend/noop.h> |
11 | #include <wlr/backend/session.h> | 11 | #include <wlr/backend/session.h> |
12 | #include <wlr/config.h> | ||
12 | #include <wlr/render/wlr_renderer.h> | 13 | #include <wlr/render/wlr_renderer.h> |
13 | #include <wlr/types/wlr_compositor.h> | 14 | #include <wlr/types/wlr_compositor.h> |
14 | #include <wlr/types/wlr_data_control_v1.h> | 15 | #include <wlr/types/wlr_data_control_v1.h> |
16 | #include <wlr/types/wlr_drm_lease_v1.h> | ||
15 | #include <wlr/types/wlr_export_dmabuf_v1.h> | 17 | #include <wlr/types/wlr_export_dmabuf_v1.h> |
16 | #include <wlr/types/wlr_gamma_control_v1.h> | 18 | #include <wlr/types/wlr_gamma_control_v1.h> |
17 | #include <wlr/types/wlr_idle.h> | 19 | #include <wlr/types/wlr_idle.h> |
@@ -24,7 +26,11 @@ | |||
24 | #include <wlr/types/wlr_tablet_v2.h> | 26 | #include <wlr/types/wlr_tablet_v2.h> |
25 | #include <wlr/types/wlr_viewporter.h> | 27 | #include <wlr/types/wlr_viewporter.h> |
26 | #include <wlr/types/wlr_xcursor_manager.h> | 28 | #include <wlr/types/wlr_xcursor_manager.h> |
29 | #include <wlr/types/wlr_xdg_activation_v1.h> | ||
27 | #include <wlr/types/wlr_xdg_decoration_v1.h> | 30 | #include <wlr/types/wlr_xdg_decoration_v1.h> |
31 | #include <wlr/types/wlr_xdg_foreign_registry.h> | ||
32 | #include <wlr/types/wlr_xdg_foreign_v1.h> | ||
33 | #include <wlr/types/wlr_xdg_foreign_v2.h> | ||
28 | #include <wlr/types/wlr_xdg_output_v1.h> | 34 | #include <wlr/types/wlr_xdg_output_v1.h> |
29 | #include "config.h" | 35 | #include "config.h" |
30 | #include "list.h" | 36 | #include "list.h" |
@@ -52,6 +58,18 @@ bool server_privileged_prepare(struct sway_server *server) { | |||
52 | return true; | 58 | return true; |
53 | } | 59 | } |
54 | 60 | ||
61 | static void handle_drm_lease_request(struct wl_listener *listener, void *data) { | ||
62 | /* We only offer non-desktop outputs, but in the future we might want to do | ||
63 | * more logic here. */ | ||
64 | |||
65 | struct wlr_drm_lease_request_v1 *req = data; | ||
66 | struct wlr_drm_lease_v1 *lease = wlr_drm_lease_request_v1_grant(req); | ||
67 | if (!lease) { | ||
68 | sway_log(SWAY_ERROR, "Failed to grant lease request"); | ||
69 | wlr_drm_lease_request_v1_reject(req); | ||
70 | } | ||
71 | } | ||
72 | |||
55 | bool server_init(struct sway_server *server) { | 73 | bool server_init(struct sway_server *server) { |
56 | sway_log(SWAY_DEBUG, "Initializing Wayland server"); | 74 | sway_log(SWAY_DEBUG, "Initializing Wayland server"); |
57 | 75 | ||
@@ -144,12 +162,34 @@ bool server_init(struct sway_server *server) { | |||
144 | server->foreign_toplevel_manager = | 162 | server->foreign_toplevel_manager = |
145 | wlr_foreign_toplevel_manager_v1_create(server->wl_display); | 163 | wlr_foreign_toplevel_manager_v1_create(server->wl_display); |
146 | 164 | ||
165 | server->drm_lease_manager= | ||
166 | wlr_drm_lease_v1_manager_create(server->wl_display, server->backend); | ||
167 | if (server->drm_lease_manager) { | ||
168 | server->drm_lease_request.notify = handle_drm_lease_request; | ||
169 | wl_signal_add(&server->drm_lease_manager->events.request, | ||
170 | &server->drm_lease_request); | ||
171 | } else { | ||
172 | sway_log(SWAY_DEBUG, "Failed to create wlr_drm_lease_device_v1"); | ||
173 | sway_log(SWAY_INFO, "VR will not be available"); | ||
174 | } | ||
175 | |||
147 | wlr_export_dmabuf_manager_v1_create(server->wl_display); | 176 | wlr_export_dmabuf_manager_v1_create(server->wl_display); |
148 | wlr_screencopy_manager_v1_create(server->wl_display); | 177 | wlr_screencopy_manager_v1_create(server->wl_display); |
149 | wlr_data_control_manager_v1_create(server->wl_display); | 178 | wlr_data_control_manager_v1_create(server->wl_display); |
150 | wlr_primary_selection_v1_device_manager_create(server->wl_display); | 179 | wlr_primary_selection_v1_device_manager_create(server->wl_display); |
151 | wlr_viewporter_create(server->wl_display); | 180 | wlr_viewporter_create(server->wl_display); |
152 | 181 | ||
182 | struct wlr_xdg_foreign_registry *foreign_registry = | ||
183 | wlr_xdg_foreign_registry_create(server->wl_display); | ||
184 | wlr_xdg_foreign_v1_create(server->wl_display, foreign_registry); | ||
185 | wlr_xdg_foreign_v2_create(server->wl_display, foreign_registry); | ||
186 | |||
187 | server->xdg_activation_v1 = wlr_xdg_activation_v1_create(server->wl_display); | ||
188 | server->xdg_activation_v1_request_activate.notify = | ||
189 | xdg_activation_v1_handle_request_activate; | ||
190 | wl_signal_add(&server->xdg_activation_v1->events.request_activate, | ||
191 | &server->xdg_activation_v1_request_activate); | ||
192 | |||
153 | // Avoid using "wayland-0" as display socket | 193 | // Avoid using "wayland-0" as display socket |
154 | char name_candidate[16]; | 194 | char name_candidate[16]; |
155 | for (int i = 1; i <= 32; ++i) { | 195 | for (int i = 1; i <= 32; ++i) { |
@@ -186,7 +226,6 @@ bool server_init(struct sway_server *server) { | |||
186 | } | 226 | } |
187 | 227 | ||
188 | server->dirty_nodes = create_list(); | 228 | server->dirty_nodes = create_list(); |
189 | server->transactions = create_list(); | ||
190 | 229 | ||
191 | server->input = input_manager_create(server); | 230 | server->input = input_manager_create(server); |
192 | input_manager_get_default_seat(); // create seat0 | 231 | input_manager_get_default_seat(); // create seat0 |
@@ -202,7 +241,6 @@ void server_fini(struct sway_server *server) { | |||
202 | wl_display_destroy_clients(server->wl_display); | 241 | wl_display_destroy_clients(server->wl_display); |
203 | wl_display_destroy(server->wl_display); | 242 | wl_display_destroy(server->wl_display); |
204 | list_free(server->dirty_nodes); | 243 | list_free(server->dirty_nodes); |
205 | list_free(server->transactions); | ||
206 | } | 244 | } |
207 | 245 | ||
208 | bool server_start(struct sway_server *server) { | 246 | bool server_start(struct sway_server *server) { |
diff --git a/sway/sway-bar.5.scd b/sway/sway-bar.5.scd index 80d08449..42e59d57 100644 --- a/sway/sway-bar.5.scd +++ b/sway/sway-bar.5.scd | |||
@@ -40,7 +40,7 @@ runtime. | |||
40 | *font* <font> | 40 | *font* <font> |
41 | Specifies the font to be used in the bar. _font_ should be specified as a | 41 | Specifies the font to be used in the bar. _font_ should be specified as a |
42 | pango font description. For more information on pango font descriptions, | 42 | pango font description. For more information on pango font descriptions, |
43 | see https://developer.gnome.org/pango/stable/pango-Fonts.html#pango-font-description-from-string | 43 | see https://docs.gtk.org/Pango/type_func.FontDescription.from_string.html#description |
44 | 44 | ||
45 | *gaps* <all> | <horizontal> <vertical> | <top> <right> <bottom> <left> | 45 | *gaps* <all> | <horizontal> <vertical> | <top> <right> <bottom> <left> |
46 | Sets the gaps from the edge of the screen for the bar. Gaps can either be | 46 | Sets the gaps from the edge of the screen for the bar. Gaps can either be |
diff --git a/sway/sway-input.5.scd b/sway/sway-input.5.scd index dbf21d93..8b702b77 100644 --- a/sway/sway-input.5.scd +++ b/sway/sway-input.5.scd | |||
@@ -111,6 +111,9 @@ The following commands may only be used in the configuration file. | |||
111 | Maps inputs from this device to the specified output. Only meaningful if the | 111 | Maps inputs from this device to the specified output. Only meaningful if the |
112 | device is a pointer, touch, or drawing tablet device. | 112 | device is a pointer, touch, or drawing tablet device. |
113 | 113 | ||
114 | The wildcard _\*_ can be used to map the input device to the whole desktop | ||
115 | layout. | ||
116 | |||
114 | *input* <identifier> map_to_region <X> <Y> <width> <height> | 117 | *input* <identifier> map_to_region <X> <Y> <width> <height> |
115 | Maps inputs from this device to the specified region of the global output | 118 | Maps inputs from this device to the specified region of the global output |
116 | layout. Only meaningful if the device is a pointer, touch, or drawing tablet | 119 | layout. Only meaningful if the device is a pointer, touch, or drawing tablet |
@@ -230,7 +233,7 @@ correct seat. | |||
230 | not explicitly attached to another seat (similar to a "default" seat). | 233 | not explicitly attached to another seat (similar to a "default" seat). |
231 | 234 | ||
232 | *seat* <name> hide_cursor <timeout>|when-typing [enable|disable] | 235 | *seat* <name> hide_cursor <timeout>|when-typing [enable|disable] |
233 | Hides the cursor image after the specified event occured. | 236 | Hides the cursor image after the specified event occurred. |
234 | 237 | ||
235 | If _timeout_ is specified, then the cursor will be hidden after _timeout_ | 238 | If _timeout_ is specified, then the cursor will be hidden after _timeout_ |
236 | (in milliseconds) has elapsed with no activity on the cursor. A timeout of 0 | 239 | (in milliseconds) has elapsed with no activity on the cursor. A timeout of 0 |
@@ -274,7 +277,7 @@ correct seat. | |||
274 | whether future inhibitors are honoured by default, i.e. activated | 277 | whether future inhibitors are honoured by default, i.e. activated |
275 | automatically, the default being _enable_. When used at runtime, | 278 | automatically, the default being _enable_. When used at runtime, |
276 | _disable_ also disables any currently active inhibitors. _activate_, | 279 | _disable_ also disables any currently active inhibitors. _activate_, |
277 | _deactivate_ and _toggle_ are only useable at runtime and change the | 280 | _deactivate_ and _toggle_ are only usable at runtime and change the |
278 | state of a potentially existing inhibitor on the currently focused | 281 | state of a potentially existing inhibitor on the currently focused |
279 | window. This can be used with the current seat alias (_-_) to affect | 282 | window. This can be used with the current seat alias (_-_) to affect |
280 | only the currently focused window of the current seat. Subcommand | 283 | only the currently focused window of the current seat. Subcommand |
diff --git a/sway/sway-ipc.7.scd b/sway/sway-ipc.7.scd index 1b855959..d90fe97a 100644 --- a/sway/sway-ipc.7.scd +++ b/sway/sway-ipc.7.scd | |||
@@ -294,7 +294,7 @@ following properties: | |||
294 | Retrieve a JSON representation of the tree | 294 | Retrieve a JSON representation of the tree |
295 | 295 | ||
296 | *REPLY*++ | 296 | *REPLY*++ |
297 | An array of object the represent the current tree. Each object represents one | 297 | An array of objects that represent the current tree. Each object represents one |
298 | node and will have the following properties: | 298 | node and will have the following properties: |
299 | 299 | ||
300 | [- *PROPERTY* | 300 | [- *PROPERTY* |
@@ -1131,6 +1131,9 @@ following properties: | |||
1131 | |- xkb_active_layout_index | 1131 | |- xkb_active_layout_index |
1132 | : integer | 1132 | : integer |
1133 | : (Only keyboards) The index of the active keyboard layout in use | 1133 | : (Only keyboards) The index of the active keyboard layout in use |
1134 | |- scroll_factor | ||
1135 | : floating | ||
1136 | : (Only pointers) Multiplier applied on scroll event values. | ||
1134 | |- libinput | 1137 | |- libinput |
1135 | : object | 1138 | : object |
1136 | : (Only libinput devices) An object describing the current device settings. | 1139 | : (Only libinput devices) An object describing the current device settings. |
diff --git a/sway/sway-output.5.scd b/sway/sway-output.5.scd index 69f529fe..55d8f719 100644 --- a/sway/sway-output.5.scd +++ b/sway/sway-output.5.scd | |||
@@ -40,6 +40,16 @@ must be separated by one space. For example: | |||
40 | 40 | ||
41 | output HDMI-A-1 mode 1920x1080@60Hz | 41 | output HDMI-A-1 mode 1920x1080@60Hz |
42 | 42 | ||
43 | *output* <name> modeline <clock> <hdisplay> <hsync_start> <hsync_end> <htotal> <vdisplay> <vsync_start> <vsync_end> <vtotal> <hsync> <vsync> | ||
44 | Configures the specified output to use the given modeline. It can be | ||
45 | generated using *cvt*(1) and *gtf*(1) commands. See *xorg.conf*(5). | ||
46 | Only supported on DRM backend. | ||
47 | |||
48 | Example: | ||
49 | |||
50 | output HDMI-A-1 modeline 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync | ||
51 | |||
52 | |||
43 | *output* <name> position|pos <X> <Y> | 53 | *output* <name> position|pos <X> <Y> |
44 | Places the specified output at the specific position in the global | 54 | Places the specified output at the specific position in the global |
45 | coordinate space. The cursor may only be moved between immediately | 55 | coordinate space. The cursor may only be moved between immediately |
@@ -112,7 +122,7 @@ must be separated by one space. For example: | |||
112 | *output* <name> toggle | 122 | *output* <name> toggle |
113 | Toggle the specified output. | 123 | Toggle the specified output. |
114 | 124 | ||
115 | *output* <name> dpms on|off | 125 | *output* <name> dpms on|off|toggle |
116 | Enables or disables the specified output via DPMS. To turn an output off | 126 | Enables or disables the specified output via DPMS. To turn an output off |
117 | (ie. blank the screen but keep workspaces as-is), one can set DPMS to off. | 127 | (ie. blank the screen but keep workspaces as-is), one can set DPMS to off. |
118 | 128 | ||
@@ -142,7 +152,7 @@ must be separated by one space. For example: | |||
142 | Enables or disables adaptive synchronization (often referred to as Variable | 152 | Enables or disables adaptive synchronization (often referred to as Variable |
143 | Refresh Rate, or by the vendor-specific names FreeSync/G-Sync). | 153 | Refresh Rate, or by the vendor-specific names FreeSync/G-Sync). |
144 | 154 | ||
145 | Adaptive sync allows clients to submit frames a little to late without | 155 | Adaptive sync allows clients to submit frames a little too late without |
146 | having to wait a whole refresh period to display it on screen. Enabling | 156 | having to wait a whole refresh period to display it on screen. Enabling |
147 | adaptive sync can improve latency, but can cause flickering on some | 157 | adaptive sync can improve latency, but can cause flickering on some |
148 | hardware. | 158 | hardware. |
diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 02592b5f..202cd13f 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd | |||
@@ -155,7 +155,7 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). | |||
155 | is specified, the view will be fullscreen across all outputs. | 155 | is specified, the view will be fullscreen across all outputs. |
156 | 156 | ||
157 | *gaps* inner|outer|horizontal|vertical|top|right|bottom|left all|current | 157 | *gaps* inner|outer|horizontal|vertical|top|right|bottom|left all|current |
158 | set|plus|minus <amount> | 158 | set|plus|minus|toggle <amount> |
159 | Changes the _inner_ or _outer_ gaps for either _all_ workspaces or the | 159 | Changes the _inner_ or _outer_ gaps for either _all_ workspaces or the |
160 | _current_ workspace. _outer_ gaps can be altered per side with _top_, | 160 | _current_ workspace. _outer_ gaps can be altered per side with _top_, |
161 | _right_, _bottom_, and _left_ or per direction with _horizontal_ and | 161 | _right_, _bottom_, and _left_ or per direction with _horizontal_ and |
@@ -215,7 +215,7 @@ set|plus|minus <amount> | |||
215 | If unspecified, the default is 10 pixels. Pixels are ignored when moving | 215 | If unspecified, the default is 10 pixels. Pixels are ignored when moving |
216 | tiled containers. | 216 | tiled containers. |
217 | 217 | ||
218 | *move* [absolute] position <pos_x> [px|ppt] <pos_y> [px|ptt] | 218 | *move* [absolute] position <pos_x> [px|ppt] <pos_y> [px|ppt] |
219 | Moves the focused container to the specified position in the workspace. | 219 | Moves the focused container to the specified position in the workspace. |
220 | The position can be specified in pixels or percentage points, omitting | 220 | The position can be specified in pixels or percentage points, omitting |
221 | the unit defaults to pixels. If _absolute_ is used, the position is | 221 | the unit defaults to pixels. If _absolute_ is used, the position is |
@@ -319,8 +319,10 @@ set|plus|minus <amount> | |||
319 | established by the *seat* subcommand of the same name. See | 319 | established by the *seat* subcommand of the same name. See |
320 | *sway-input*(5) for more ways to affect inhibitors. | 320 | *sway-input*(5) for more ways to affect inhibitors. |
321 | 321 | ||
322 | *split* vertical|v|horizontal|h|toggle|t | 322 | *split* vertical|v|horizontal|h|none|n|toggle|t |
323 | Splits the current container, vertically or horizontally. When _toggle_ is | 323 | Splits the current container, vertically or horizontally. When _none_ is |
324 | specified, the effect of a previous split is undone if the current | ||
325 | container is the only child of a split parent. When _toggle_ is | ||
324 | specified, the current container is split opposite to the parent | 326 | specified, the current container is split opposite to the parent |
325 | container's layout. | 327 | container's layout. |
326 | 328 | ||
@@ -630,7 +632,7 @@ The default colors are: | |||
630 | should be used instead. Regardless of whether pango markup is enabled, | 632 | should be used instead. Regardless of whether pango markup is enabled, |
631 | _font_ should be specified as a pango font description. For more | 633 | _font_ should be specified as a pango font description. For more |
632 | information on pango font descriptions, see | 634 | information on pango font descriptions, see |
633 | https://developer.gnome.org/pango/stable/pango-Fonts.html#pango-font-description-from-string | 635 | https://docs.gtk.org/Pango/type_func.FontDescription.from_string.html#description |
634 | 636 | ||
635 | *force_display_urgency_hint* <timeout> [ms] | 637 | *force_display_urgency_hint* <timeout> [ms] |
636 | If an application on another workspace sets an urgency hint, switching to this | 638 | If an application on another workspace sets an urgency hint, switching to this |
diff --git a/sway/swaynag.c b/sway/swaynag.c index db5a919a..ba582989 100644 --- a/sway/swaynag.c +++ b/sway/swaynag.c | |||
@@ -87,8 +87,8 @@ bool swaynag_spawn(const char *swaynag_command, | |||
87 | size_t length = strlen(swaynag_command) + strlen(swaynag->args) + 2; | 87 | size_t length = strlen(swaynag_command) + strlen(swaynag->args) + 2; |
88 | char *cmd = malloc(length); | 88 | char *cmd = malloc(length); |
89 | snprintf(cmd, length, "%s %s", swaynag_command, swaynag->args); | 89 | snprintf(cmd, length, "%s %s", swaynag_command, swaynag->args); |
90 | execl("/bin/sh", "/bin/sh", "-c", cmd, NULL); | 90 | execlp("sh", "sh", "-c", cmd, NULL); |
91 | sway_log_errno(SWAY_ERROR, "execl failed"); | 91 | sway_log_errno(SWAY_ERROR, "execlp failed"); |
92 | _exit(EXIT_FAILURE); | 92 | _exit(EXIT_FAILURE); |
93 | } | 93 | } |
94 | _exit(EXIT_SUCCESS); | 94 | _exit(EXIT_SUCCESS); |
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index bac9f2fa..4aa82c35 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c | |||
@@ -55,7 +55,7 @@ static void apply_horiz_layout(list_t *children, struct wlr_box *parent) { | |||
55 | // Calculate gap size | 55 | // Calculate gap size |
56 | double inner_gap = 0; | 56 | double inner_gap = 0; |
57 | struct sway_container *child = children->items[0]; | 57 | struct sway_container *child = children->items[0]; |
58 | struct sway_workspace *ws = child->workspace; | 58 | struct sway_workspace *ws = child->pending.workspace; |
59 | if (ws) { | 59 | if (ws) { |
60 | inner_gap = ws->gaps_inner; | 60 | inner_gap = ws->gaps_inner; |
61 | } | 61 | } |
@@ -66,7 +66,7 @@ static void apply_horiz_layout(list_t *children, struct wlr_box *parent) { | |||
66 | if (layout == L_TABBED || layout == L_STACKED) { | 66 | if (layout == L_TABBED || layout == L_STACKED) { |
67 | inner_gap = 0; | 67 | inner_gap = 0; |
68 | } | 68 | } |
69 | temp = temp->parent; | 69 | temp = temp->pending.parent; |
70 | } | 70 | } |
71 | double total_gap = fmin(inner_gap * (children->length - 1), | 71 | double total_gap = fmin(inner_gap * (children->length - 1), |
72 | fmax(0, parent->width - MIN_SANE_W * children->length)); | 72 | fmax(0, parent->width - MIN_SANE_W * children->length)); |
@@ -79,15 +79,15 @@ static void apply_horiz_layout(list_t *children, struct wlr_box *parent) { | |||
79 | for (int i = 0; i < children->length; ++i) { | 79 | for (int i = 0; i < children->length; ++i) { |
80 | struct sway_container *child = children->items[i]; | 80 | struct sway_container *child = children->items[i]; |
81 | child->child_total_width = child_total_width; | 81 | child->child_total_width = child_total_width; |
82 | child->x = child_x; | 82 | child->pending.x = child_x; |
83 | child->y = parent->y; | 83 | child->pending.y = parent->y; |
84 | child->width = round(child->width_fraction * child_total_width); | 84 | child->pending.width = round(child->width_fraction * child_total_width); |
85 | child->height = parent->height; | 85 | child->pending.height = parent->height; |
86 | child_x += child->width + inner_gap; | 86 | child_x += child->pending.width + inner_gap; |
87 | 87 | ||
88 | // Make last child use remaining width of parent | 88 | // Make last child use remaining width of parent |
89 | if (i == children->length - 1) { | 89 | if (i == children->length - 1) { |
90 | child->width = parent->x + parent->width - child->x; | 90 | child->pending.width = parent->x + parent->width - child->pending.x; |
91 | } | 91 | } |
92 | } | 92 | } |
93 | } | 93 | } |
@@ -134,7 +134,7 @@ static void apply_vert_layout(list_t *children, struct wlr_box *parent) { | |||
134 | // Calculate gap size | 134 | // Calculate gap size |
135 | double inner_gap = 0; | 135 | double inner_gap = 0; |
136 | struct sway_container *child = children->items[0]; | 136 | struct sway_container *child = children->items[0]; |
137 | struct sway_workspace *ws = child->workspace; | 137 | struct sway_workspace *ws = child->pending.workspace; |
138 | if (ws) { | 138 | if (ws) { |
139 | inner_gap = ws->gaps_inner; | 139 | inner_gap = ws->gaps_inner; |
140 | } | 140 | } |
@@ -145,7 +145,7 @@ static void apply_vert_layout(list_t *children, struct wlr_box *parent) { | |||
145 | if (layout == L_TABBED || layout == L_STACKED) { | 145 | if (layout == L_TABBED || layout == L_STACKED) { |
146 | inner_gap = 0; | 146 | inner_gap = 0; |
147 | } | 147 | } |
148 | temp = temp->parent; | 148 | temp = temp->pending.parent; |
149 | } | 149 | } |
150 | double total_gap = fmin(inner_gap * (children->length - 1), | 150 | double total_gap = fmin(inner_gap * (children->length - 1), |
151 | fmax(0, parent->height - MIN_SANE_H * children->length)); | 151 | fmax(0, parent->height - MIN_SANE_H * children->length)); |
@@ -158,15 +158,15 @@ static void apply_vert_layout(list_t *children, struct wlr_box *parent) { | |||
158 | for (int i = 0; i < children->length; ++i) { | 158 | for (int i = 0; i < children->length; ++i) { |
159 | struct sway_container *child = children->items[i]; | 159 | struct sway_container *child = children->items[i]; |
160 | child->child_total_height = child_total_height; | 160 | child->child_total_height = child_total_height; |
161 | child->x = parent->x; | 161 | child->pending.x = parent->x; |
162 | child->y = child_y; | 162 | child->pending.y = child_y; |
163 | child->width = parent->width; | 163 | child->pending.width = parent->width; |
164 | child->height = round(child->height_fraction * child_total_height); | 164 | child->pending.height = round(child->height_fraction * child_total_height); |
165 | child_y += child->height + inner_gap; | 165 | child_y += child->pending.height + inner_gap; |
166 | 166 | ||
167 | // Make last child use remaining height of parent | 167 | // Make last child use remaining height of parent |
168 | if (i == children->length - 1) { | 168 | if (i == children->length - 1) { |
169 | child->height = parent->y + parent->height - child->y; | 169 | child->pending.height = parent->y + parent->height - child->pending.y; |
170 | } | 170 | } |
171 | } | 171 | } |
172 | } | 172 | } |
@@ -178,10 +178,10 @@ static void apply_tabbed_layout(list_t *children, struct wlr_box *parent) { | |||
178 | for (int i = 0; i < children->length; ++i) { | 178 | for (int i = 0; i < children->length; ++i) { |
179 | struct sway_container *child = children->items[i]; | 179 | struct sway_container *child = children->items[i]; |
180 | int parent_offset = child->view ? 0 : container_titlebar_height(); | 180 | int parent_offset = child->view ? 0 : container_titlebar_height(); |
181 | child->x = parent->x; | 181 | child->pending.x = parent->x; |
182 | child->y = parent->y + parent_offset; | 182 | child->pending.y = parent->y + parent_offset; |
183 | child->width = parent->width; | 183 | child->pending.width = parent->width; |
184 | child->height = parent->height - parent_offset; | 184 | child->pending.height = parent->height - parent_offset; |
185 | } | 185 | } |
186 | } | 186 | } |
187 | 187 | ||
@@ -193,10 +193,10 @@ static void apply_stacked_layout(list_t *children, struct wlr_box *parent) { | |||
193 | struct sway_container *child = children->items[i]; | 193 | struct sway_container *child = children->items[i]; |
194 | int parent_offset = child->view ? 0 : | 194 | int parent_offset = child->view ? 0 : |
195 | container_titlebar_height() * children->length; | 195 | container_titlebar_height() * children->length; |
196 | child->x = parent->x; | 196 | child->pending.x = parent->x; |
197 | child->y = parent->y + parent_offset; | 197 | child->pending.y = parent->y + parent_offset; |
198 | child->width = parent->width; | 198 | child->pending.width = parent->width; |
199 | child->height = parent->height - parent_offset; | 199 | child->pending.height = parent->height - parent_offset; |
200 | } | 200 | } |
201 | } | 201 | } |
202 | 202 | ||
@@ -246,7 +246,7 @@ void arrange_container(struct sway_container *container) { | |||
246 | } | 246 | } |
247 | struct wlr_box box; | 247 | struct wlr_box box; |
248 | container_get_box(container, &box); | 248 | container_get_box(container, &box); |
249 | arrange_children(container->children, container->layout, &box); | 249 | arrange_children(container->pending.children, container->pending.layout, &box); |
250 | node_set_dirty(&container->node); | 250 | node_set_dirty(&container->node); |
251 | } | 251 | } |
252 | 252 | ||
@@ -278,8 +278,8 @@ void arrange_workspace(struct sway_workspace *workspace) { | |||
278 | for (int i = 0; i < workspace->floating->length; ++i) { | 278 | for (int i = 0; i < workspace->floating->length; ++i) { |
279 | struct sway_container *floater = workspace->floating->items[i]; | 279 | struct sway_container *floater = workspace->floating->items[i]; |
280 | container_floating_translate(floater, diff_x, diff_y); | 280 | container_floating_translate(floater, diff_x, diff_y); |
281 | double center_x = floater->x + floater->width / 2; | 281 | double center_x = floater->pending.x + floater->pending.width / 2; |
282 | double center_y = floater->y + floater->height / 2; | 282 | double center_y = floater->pending.y + floater->pending.height / 2; |
283 | struct wlr_box workspace_box; | 283 | struct wlr_box workspace_box; |
284 | workspace_get_box(workspace, &workspace_box); | 284 | workspace_get_box(workspace, &workspace_box); |
285 | if (!wlr_box_contains_point(&workspace_box, center_x, center_y)) { | 285 | if (!wlr_box_contains_point(&workspace_box, center_x, center_y)) { |
@@ -294,10 +294,10 @@ void arrange_workspace(struct sway_workspace *workspace) { | |||
294 | workspace->x, workspace->y); | 294 | workspace->x, workspace->y); |
295 | if (workspace->fullscreen) { | 295 | if (workspace->fullscreen) { |
296 | struct sway_container *fs = workspace->fullscreen; | 296 | struct sway_container *fs = workspace->fullscreen; |
297 | fs->x = output->lx; | 297 | fs->pending.x = output->lx; |
298 | fs->y = output->ly; | 298 | fs->pending.y = output->ly; |
299 | fs->width = output->width; | 299 | fs->pending.width = output->width; |
300 | fs->height = output->height; | 300 | fs->pending.height = output->height; |
301 | arrange_container(fs); | 301 | arrange_container(fs); |
302 | } else { | 302 | } else { |
303 | struct wlr_box box; | 303 | struct wlr_box box; |
@@ -337,10 +337,10 @@ void arrange_root(void) { | |||
337 | 337 | ||
338 | if (root->fullscreen_global) { | 338 | if (root->fullscreen_global) { |
339 | struct sway_container *fs = root->fullscreen_global; | 339 | struct sway_container *fs = root->fullscreen_global; |
340 | fs->x = root->x; | 340 | fs->pending.x = root->x; |
341 | fs->y = root->y; | 341 | fs->pending.y = root->y; |
342 | fs->width = root->width; | 342 | fs->pending.width = root->width; |
343 | fs->height = root->height; | 343 | fs->pending.height = root->height; |
344 | arrange_container(fs); | 344 | arrange_container(fs); |
345 | } else { | 345 | } else { |
346 | for (int i = 0; i < root->outputs->length; ++i) { | 346 | for (int i = 0; i < root->outputs->length; ++i) { |
diff --git a/sway/tree/container.c b/sway/tree/container.c index 6a9ce1c4..6a01eab3 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -1,12 +1,13 @@ | |||
1 | #define _POSIX_C_SOURCE 200809L | 1 | #define _POSIX_C_SOURCE 200809L |
2 | #include <assert.h> | 2 | #include <assert.h> |
3 | #include <drm_fourcc.h> | ||
3 | #include <stdint.h> | 4 | #include <stdint.h> |
4 | #include <stdlib.h> | 5 | #include <stdlib.h> |
5 | #include <string.h> | 6 | #include <string.h> |
6 | #include <strings.h> | 7 | #include <strings.h> |
7 | #include <wayland-server-core.h> | 8 | #include <wayland-server-core.h> |
8 | #include <wlr/types/wlr_output_layout.h> | 9 | #include <wlr/types/wlr_output_layout.h> |
9 | #include "cairo.h" | 10 | #include "cairo_util.h" |
10 | #include "pango.h" | 11 | #include "pango.h" |
11 | #include "sway/config.h" | 12 | #include "sway/config.h" |
12 | #include "sway/desktop.h" | 13 | #include "sway/desktop.h" |
@@ -19,6 +20,7 @@ | |||
19 | #include "sway/tree/arrange.h" | 20 | #include "sway/tree/arrange.h" |
20 | #include "sway/tree/view.h" | 21 | #include "sway/tree/view.h" |
21 | #include "sway/tree/workspace.h" | 22 | #include "sway/tree/workspace.h" |
23 | #include "sway/xdg_decoration.h" | ||
22 | #include "list.h" | 24 | #include "list.h" |
23 | #include "log.h" | 25 | #include "log.h" |
24 | #include "stringop.h" | 26 | #include "stringop.h" |
@@ -30,12 +32,12 @@ struct sway_container *container_create(struct sway_view *view) { | |||
30 | return NULL; | 32 | return NULL; |
31 | } | 33 | } |
32 | node_init(&c->node, N_CONTAINER, c); | 34 | node_init(&c->node, N_CONTAINER, c); |
33 | c->layout = L_NONE; | 35 | c->pending.layout = L_NONE; |
34 | c->view = view; | 36 | c->view = view; |
35 | c->alpha = 1.0f; | 37 | c->alpha = 1.0f; |
36 | 38 | ||
37 | if (!view) { | 39 | if (!view) { |
38 | c->children = create_list(); | 40 | c->pending.children = create_list(); |
39 | c->current.children = create_list(); | 41 | c->current.children = create_list(); |
40 | } | 42 | } |
41 | c->marks = create_list(); | 43 | c->marks = create_list(); |
@@ -62,7 +64,7 @@ void container_destroy(struct sway_container *con) { | |||
62 | wlr_texture_destroy(con->title_focused_inactive); | 64 | wlr_texture_destroy(con->title_focused_inactive); |
63 | wlr_texture_destroy(con->title_unfocused); | 65 | wlr_texture_destroy(con->title_unfocused); |
64 | wlr_texture_destroy(con->title_urgent); | 66 | wlr_texture_destroy(con->title_urgent); |
65 | list_free(con->children); | 67 | list_free(con->pending.children); |
66 | list_free(con->current.children); | 68 | list_free(con->current.children); |
67 | list_free(con->outputs); | 69 | list_free(con->outputs); |
68 | 70 | ||
@@ -90,10 +92,10 @@ void container_begin_destroy(struct sway_container *con) { | |||
90 | } | 92 | } |
91 | // The workspace must have the fullscreen pointer cleared so that the | 93 | // The workspace must have the fullscreen pointer cleared so that the |
92 | // seat code can find an appropriate new focus. | 94 | // seat code can find an appropriate new focus. |
93 | if (con->fullscreen_mode == FULLSCREEN_WORKSPACE && con->workspace) { | 95 | if (con->pending.fullscreen_mode == FULLSCREEN_WORKSPACE && con->pending.workspace) { |
94 | con->workspace->fullscreen = NULL; | 96 | con->pending.workspace->fullscreen = NULL; |
95 | } | 97 | } |
96 | if (con->scratchpad && con->fullscreen_mode == FULLSCREEN_GLOBAL) { | 98 | if (con->scratchpad && con->pending.fullscreen_mode == FULLSCREEN_GLOBAL) { |
97 | container_fullscreen_disable(con); | 99 | container_fullscreen_disable(con); |
98 | } | 100 | } |
99 | 101 | ||
@@ -108,11 +110,11 @@ void container_begin_destroy(struct sway_container *con) { | |||
108 | root_scratchpad_remove_container(con); | 110 | root_scratchpad_remove_container(con); |
109 | } | 111 | } |
110 | 112 | ||
111 | if (con->fullscreen_mode == FULLSCREEN_GLOBAL) { | 113 | if (con->pending.fullscreen_mode == FULLSCREEN_GLOBAL) { |
112 | container_fullscreen_disable(con); | 114 | container_fullscreen_disable(con); |
113 | } | 115 | } |
114 | 116 | ||
115 | if (con->parent || con->workspace) { | 117 | if (con->pending.parent || con->pending.workspace) { |
116 | container_detach(con); | 118 | container_detach(con); |
117 | } | 119 | } |
118 | } | 120 | } |
@@ -121,12 +123,12 @@ void container_reap_empty(struct sway_container *con) { | |||
121 | if (con->view) { | 123 | if (con->view) { |
122 | return; | 124 | return; |
123 | } | 125 | } |
124 | struct sway_workspace *ws = con->workspace; | 126 | struct sway_workspace *ws = con->pending.workspace; |
125 | while (con) { | 127 | while (con) { |
126 | if (con->children->length) { | 128 | if (con->pending.children->length) { |
127 | return; | 129 | return; |
128 | } | 130 | } |
129 | struct sway_container *parent = con->parent; | 131 | struct sway_container *parent = con->pending.parent; |
130 | container_begin_destroy(con); | 132 | container_begin_destroy(con); |
131 | con = parent; | 133 | con = parent; |
132 | } | 134 | } |
@@ -139,9 +141,9 @@ struct sway_container *container_flatten(struct sway_container *container) { | |||
139 | if (container->view) { | 141 | if (container->view) { |
140 | return NULL; | 142 | return NULL; |
141 | } | 143 | } |
142 | while (container && container->children->length == 1) { | 144 | while (container && container->pending.children->length == 1) { |
143 | struct sway_container *child = container->children->items[0]; | 145 | struct sway_container *child = container->pending.children->items[0]; |
144 | struct sway_container *parent = container->parent; | 146 | struct sway_container *parent = container->pending.parent; |
145 | container_replace(container, child); | 147 | container_replace(container, child); |
146 | container_begin_destroy(container); | 148 | container_begin_destroy(container); |
147 | container = parent; | 149 | container = parent; |
@@ -151,11 +153,11 @@ struct sway_container *container_flatten(struct sway_container *container) { | |||
151 | 153 | ||
152 | struct sway_container *container_find_child(struct sway_container *container, | 154 | struct sway_container *container_find_child(struct sway_container *container, |
153 | bool (*test)(struct sway_container *con, void *data), void *data) { | 155 | bool (*test)(struct sway_container *con, void *data), void *data) { |
154 | if (!container->children) { | 156 | if (!container->pending.children) { |
155 | return NULL; | 157 | return NULL; |
156 | } | 158 | } |
157 | for (int i = 0; i < container->children->length; ++i) { | 159 | for (int i = 0; i < container->pending.children->length; ++i) { |
158 | struct sway_container *child = container->children->items[i]; | 160 | struct sway_container *child = container->pending.children->items[i]; |
159 | if (test(child, data)) { | 161 | if (test(child, data)) { |
160 | return child; | 162 | return child; |
161 | } | 163 | } |
@@ -310,7 +312,7 @@ static struct sway_container *floating_container_at(double lx, double ly, | |||
310 | return NULL; | 312 | return NULL; |
311 | } | 313 | } |
312 | 314 | ||
313 | struct sway_container *view_container_at(struct sway_node *parent, | 315 | static struct sway_container *view_container_content_at(struct sway_node *parent, |
314 | double lx, double ly, | 316 | double lx, double ly, |
315 | struct wlr_surface **surface, double *sx, double *sy) { | 317 | struct wlr_surface **surface, double *sx, double *sy) { |
316 | if (!sway_assert(node_is_view(parent), "Expected a view")) { | 318 | if (!sway_assert(node_is_view(parent), "Expected a view")) { |
@@ -319,10 +321,33 @@ struct sway_container *view_container_at(struct sway_node *parent, | |||
319 | 321 | ||
320 | struct sway_container *container = parent->sway_container; | 322 | struct sway_container *container = parent->sway_container; |
321 | struct wlr_box box = { | 323 | struct wlr_box box = { |
322 | .x = container->x, | 324 | .x = container->pending.content_x, |
323 | .y = container->y, | 325 | .y = container->pending.content_y, |
324 | .width = container->width, | 326 | .width = container->pending.content_width, |
325 | .height = container->height, | 327 | .height = container->pending.content_height, |
328 | }; | ||
329 | |||
330 | if (wlr_box_contains_point(&box, lx, ly)) { | ||
331 | surface_at_view(parent->sway_container, lx, ly, surface, sx, sy); | ||
332 | return container; | ||
333 | } | ||
334 | |||
335 | return NULL; | ||
336 | } | ||
337 | |||
338 | static struct sway_container *view_container_at(struct sway_node *parent, | ||
339 | double lx, double ly, | ||
340 | struct wlr_surface **surface, double *sx, double *sy) { | ||
341 | if (!sway_assert(node_is_view(parent), "Expected a view")) { | ||
342 | return NULL; | ||
343 | } | ||
344 | |||
345 | struct sway_container *container = parent->sway_container; | ||
346 | struct wlr_box box = { | ||
347 | .x = container->pending.x, | ||
348 | .y = container->pending.y, | ||
349 | .width = container->pending.width, | ||
350 | .height = container->pending.height, | ||
326 | }; | 351 | }; |
327 | 352 | ||
328 | if (wlr_box_contains_point(&box, lx, ly)) { | 353 | if (wlr_box_contains_point(&box, lx, ly)) { |
@@ -394,7 +419,7 @@ struct sway_container *container_at(struct sway_workspace *workspace, | |||
394 | } | 419 | } |
395 | // Tiling (focused) | 420 | // Tiling (focused) |
396 | if (focus && focus->view && !is_floating) { | 421 | if (focus && focus->view && !is_floating) { |
397 | if ((c = surface_at_view(focus, lx, ly, surface, sx, sy))) { | 422 | if ((c = view_container_content_at(&focus->node, lx, ly, surface, sx, sy))) { |
398 | return c; | 423 | return c; |
399 | } | 424 | } |
400 | } | 425 | } |
@@ -408,19 +433,41 @@ struct sway_container *container_at(struct sway_workspace *workspace, | |||
408 | void container_for_each_child(struct sway_container *container, | 433 | void container_for_each_child(struct sway_container *container, |
409 | void (*f)(struct sway_container *container, void *data), | 434 | void (*f)(struct sway_container *container, void *data), |
410 | void *data) { | 435 | void *data) { |
411 | if (container->children) { | 436 | if (container->pending.children) { |
412 | for (int i = 0; i < container->children->length; ++i) { | 437 | for (int i = 0; i < container->pending.children->length; ++i) { |
413 | struct sway_container *child = container->children->items[i]; | 438 | struct sway_container *child = container->pending.children->items[i]; |
414 | f(child, data); | 439 | f(child, data); |
415 | container_for_each_child(child, f, data); | 440 | container_for_each_child(child, f, data); |
416 | } | 441 | } |
417 | } | 442 | } |
418 | } | 443 | } |
419 | 444 | ||
445 | struct sway_container *container_obstructing_fullscreen_container(struct sway_container *container) | ||
446 | { | ||
447 | struct sway_workspace *workspace = container->pending.workspace; | ||
448 | |||
449 | if (workspace && workspace->fullscreen && !container_is_fullscreen_or_child(container)) { | ||
450 | if (container_is_transient_for(container, workspace->fullscreen)) { | ||
451 | return NULL; | ||
452 | } | ||
453 | return workspace->fullscreen; | ||
454 | } | ||
455 | |||
456 | struct sway_container *fullscreen_global = root->fullscreen_global; | ||
457 | if (fullscreen_global && container != fullscreen_global && !container_has_ancestor(container, fullscreen_global)) { | ||
458 | if (container_is_transient_for(container, fullscreen_global)) { | ||
459 | return NULL; | ||
460 | } | ||
461 | return fullscreen_global; | ||
462 | } | ||
463 | |||
464 | return NULL; | ||
465 | } | ||
466 | |||
420 | bool container_has_ancestor(struct sway_container *descendant, | 467 | bool container_has_ancestor(struct sway_container *descendant, |
421 | struct sway_container *ancestor) { | 468 | struct sway_container *ancestor) { |
422 | while (descendant) { | 469 | while (descendant) { |
423 | descendant = descendant->parent; | 470 | descendant = descendant->pending.parent; |
424 | if (descendant == ancestor) { | 471 | if (descendant == ancestor) { |
425 | return true; | 472 | return true; |
426 | } | 473 | } |
@@ -446,23 +493,13 @@ struct sway_output *container_get_effective_output(struct sway_container *con) { | |||
446 | return con->outputs->items[con->outputs->length - 1]; | 493 | return con->outputs->items[con->outputs->length - 1]; |
447 | } | 494 | } |
448 | 495 | ||
449 | static void update_title_texture(struct sway_container *con, | 496 | static void render_titlebar_text_texture(struct sway_output *output, |
450 | struct wlr_texture **texture, struct border_colors *class) { | 497 | struct sway_container *con, struct wlr_texture **texture, |
451 | struct sway_output *output = container_get_effective_output(con); | 498 | struct border_colors *class, bool pango_markup, char *text) { |
452 | if (!output) { | ||
453 | return; | ||
454 | } | ||
455 | if (*texture) { | ||
456 | wlr_texture_destroy(*texture); | ||
457 | *texture = NULL; | ||
458 | } | ||
459 | if (!con->formatted_title) { | ||
460 | return; | ||
461 | } | ||
462 | |||
463 | double scale = output->wlr_output->scale; | 499 | double scale = output->wlr_output->scale; |
464 | int width = 0; | 500 | int width = 0; |
465 | int height = con->title_height * scale; | 501 | int height = config->font_height * scale; |
502 | int baseline; | ||
466 | 503 | ||
467 | // We must use a non-nil cairo_t for cairo_set_font_options to work. | 504 | // We must use a non-nil cairo_t for cairo_set_font_options to work. |
468 | // Therefore, we cannot use cairo_create(NULL). | 505 | // Therefore, we cannot use cairo_create(NULL). |
@@ -480,11 +517,19 @@ static void update_title_texture(struct sway_container *con, | |||
480 | to_cairo_subpixel_order(output->wlr_output->subpixel)); | 517 | to_cairo_subpixel_order(output->wlr_output->subpixel)); |
481 | } | 518 | } |
482 | cairo_set_font_options(c, fo); | 519 | cairo_set_font_options(c, fo); |
483 | get_text_size(c, config->font, &width, NULL, NULL, scale, | 520 | get_text_size(c, config->font, &width, NULL, &baseline, scale, |
484 | config->pango_markup, "%s", con->formatted_title); | 521 | config->pango_markup, "%s", text); |
485 | cairo_surface_destroy(dummy_surface); | 522 | cairo_surface_destroy(dummy_surface); |
486 | cairo_destroy(c); | 523 | cairo_destroy(c); |
487 | 524 | ||
525 | if (width == 0 || height == 0) { | ||
526 | return; | ||
527 | } | ||
528 | |||
529 | if (height > config->font_height * scale) { | ||
530 | height = config->font_height * scale; | ||
531 | } | ||
532 | |||
488 | cairo_surface_t *surface = cairo_image_surface_create( | 533 | cairo_surface_t *surface = cairo_image_surface_create( |
489 | CAIRO_FORMAT_ARGB32, width, height); | 534 | CAIRO_FORMAT_ARGB32, width, height); |
490 | cairo_t *cairo = cairo_create(surface); | 535 | cairo_t *cairo = cairo_create(surface); |
@@ -497,23 +542,40 @@ static void update_title_texture(struct sway_container *con, | |||
497 | PangoContext *pango = pango_cairo_create_context(cairo); | 542 | PangoContext *pango = pango_cairo_create_context(cairo); |
498 | cairo_set_source_rgba(cairo, class->text[0], class->text[1], | 543 | cairo_set_source_rgba(cairo, class->text[0], class->text[1], |
499 | class->text[2], class->text[3]); | 544 | class->text[2], class->text[3]); |
500 | cairo_move_to(cairo, 0, 0); | 545 | cairo_move_to(cairo, 0, config->font_baseline * scale - baseline); |
501 | 546 | ||
502 | pango_printf(cairo, config->font, scale, config->pango_markup, | 547 | render_text(cairo, config->font, scale, pango_markup, "%s", text); |
503 | "%s", con->formatted_title); | ||
504 | 548 | ||
505 | cairo_surface_flush(surface); | 549 | cairo_surface_flush(surface); |
506 | unsigned char *data = cairo_image_surface_get_data(surface); | 550 | unsigned char *data = cairo_image_surface_get_data(surface); |
507 | int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); | 551 | int stride = cairo_image_surface_get_stride(surface); |
508 | struct wlr_renderer *renderer = wlr_backend_get_renderer( | 552 | struct wlr_renderer *renderer = wlr_backend_get_renderer( |
509 | output->wlr_output->backend); | 553 | output->wlr_output->backend); |
510 | *texture = wlr_texture_from_pixels( | 554 | *texture = wlr_texture_from_pixels( |
511 | renderer, WL_SHM_FORMAT_ARGB8888, stride, width, height, data); | 555 | renderer, DRM_FORMAT_ARGB8888, stride, width, height, data); |
512 | cairo_surface_destroy(surface); | 556 | cairo_surface_destroy(surface); |
513 | g_object_unref(pango); | 557 | g_object_unref(pango); |
514 | cairo_destroy(cairo); | 558 | cairo_destroy(cairo); |
515 | } | 559 | } |
516 | 560 | ||
561 | static void update_title_texture(struct sway_container *con, | ||
562 | struct wlr_texture **texture, struct border_colors *class) { | ||
563 | struct sway_output *output = container_get_effective_output(con); | ||
564 | if (!output) { | ||
565 | return; | ||
566 | } | ||
567 | if (*texture) { | ||
568 | wlr_texture_destroy(*texture); | ||
569 | *texture = NULL; | ||
570 | } | ||
571 | if (!con->formatted_title) { | ||
572 | return; | ||
573 | } | ||
574 | |||
575 | render_titlebar_text_texture(output, con, texture, class, | ||
576 | config->pango_markup, con->formatted_title); | ||
577 | } | ||
578 | |||
517 | void container_update_title_textures(struct sway_container *container) { | 579 | void container_update_title_textures(struct sway_container *container) { |
518 | update_title_texture(container, &container->title_focused, | 580 | update_title_texture(container, &container->title_focused, |
519 | &config->border_colors.focused); | 581 | &config->border_colors.focused); |
@@ -526,21 +588,6 @@ void container_update_title_textures(struct sway_container *container) { | |||
526 | container_damage_whole(container); | 588 | container_damage_whole(container); |
527 | } | 589 | } |
528 | 590 | ||
529 | void container_calculate_title_height(struct sway_container *container) { | ||
530 | if (!container->formatted_title) { | ||
531 | container->title_height = 0; | ||
532 | return; | ||
533 | } | ||
534 | cairo_t *cairo = cairo_create(NULL); | ||
535 | int height; | ||
536 | int baseline; | ||
537 | get_text_size(cairo, config->font, NULL, &height, &baseline, 1, | ||
538 | config->pango_markup, "%s", container->formatted_title); | ||
539 | cairo_destroy(cairo); | ||
540 | container->title_height = height; | ||
541 | container->title_baseline = baseline; | ||
542 | } | ||
543 | |||
544 | /** | 591 | /** |
545 | * Calculate and return the length of the tree representation. | 592 | * Calculate and return the length of the tree representation. |
546 | * An example tree representation is: V[Terminal, Firefox] | 593 | * An example tree representation is: V[Terminal, Firefox] |
@@ -596,23 +643,22 @@ size_t container_build_representation(enum sway_container_layout layout, | |||
596 | 643 | ||
597 | void container_update_representation(struct sway_container *con) { | 644 | void container_update_representation(struct sway_container *con) { |
598 | if (!con->view) { | 645 | if (!con->view) { |
599 | size_t len = container_build_representation(con->layout, | 646 | size_t len = container_build_representation(con->pending.layout, |
600 | con->children, NULL); | 647 | con->pending.children, NULL); |
601 | free(con->formatted_title); | 648 | free(con->formatted_title); |
602 | con->formatted_title = calloc(len + 1, sizeof(char)); | 649 | con->formatted_title = calloc(len + 1, sizeof(char)); |
603 | if (!sway_assert(con->formatted_title, | 650 | if (!sway_assert(con->formatted_title, |
604 | "Unable to allocate title string")) { | 651 | "Unable to allocate title string")) { |
605 | return; | 652 | return; |
606 | } | 653 | } |
607 | container_build_representation(con->layout, con->children, | 654 | container_build_representation(con->pending.layout, con->pending.children, |
608 | con->formatted_title); | 655 | con->formatted_title); |
609 | container_calculate_title_height(con); | ||
610 | container_update_title_textures(con); | 656 | container_update_title_textures(con); |
611 | } | 657 | } |
612 | if (con->parent) { | 658 | if (con->pending.parent) { |
613 | container_update_representation(con->parent); | 659 | container_update_representation(con->pending.parent); |
614 | } else if (con->workspace) { | 660 | } else if (con->pending.workspace) { |
615 | workspace_update_representation(con->workspace); | 661 | workspace_update_representation(con->pending.workspace); |
616 | } | 662 | } |
617 | } | 663 | } |
618 | 664 | ||
@@ -663,20 +709,20 @@ static void floating_natural_resize(struct sway_container *con) { | |||
663 | floating_calculate_constraints(&min_width, &max_width, | 709 | floating_calculate_constraints(&min_width, &max_width, |
664 | &min_height, &max_height); | 710 | &min_height, &max_height); |
665 | if (!con->view) { | 711 | if (!con->view) { |
666 | con->width = fmax(min_width, fmin(con->width, max_width)); | 712 | con->pending.width = fmax(min_width, fmin(con->pending.width, max_width)); |
667 | con->height = fmax(min_height, fmin(con->height, max_height)); | 713 | con->pending.height = fmax(min_height, fmin(con->pending.height, max_height)); |
668 | } else { | 714 | } else { |
669 | struct sway_view *view = con->view; | 715 | struct sway_view *view = con->view; |
670 | con->content_width = | 716 | con->pending.content_width = |
671 | fmax(min_width, fmin(view->natural_width, max_width)); | 717 | fmax(min_width, fmin(view->natural_width, max_width)); |
672 | con->content_height = | 718 | con->pending.content_height = |
673 | fmax(min_height, fmin(view->natural_height, max_height)); | 719 | fmax(min_height, fmin(view->natural_height, max_height)); |
674 | container_set_geometry_from_content(con); | 720 | container_set_geometry_from_content(con); |
675 | } | 721 | } |
676 | } | 722 | } |
677 | 723 | ||
678 | void container_floating_resize_and_center(struct sway_container *con) { | 724 | void container_floating_resize_and_center(struct sway_container *con) { |
679 | struct sway_workspace *ws = con->workspace; | 725 | struct sway_workspace *ws = con->pending.workspace; |
680 | if (!ws) { | 726 | if (!ws) { |
681 | // On scratchpad, just resize | 727 | // On scratchpad, just resize |
682 | floating_natural_resize(con); | 728 | floating_natural_resize(con); |
@@ -687,42 +733,42 @@ void container_floating_resize_and_center(struct sway_container *con) { | |||
687 | ws->output->wlr_output); | 733 | ws->output->wlr_output); |
688 | if (!ob) { | 734 | if (!ob) { |
689 | // On NOOP output. Will be called again when moved to an output | 735 | // On NOOP output. Will be called again when moved to an output |
690 | con->x = 0; | 736 | con->pending.x = 0; |
691 | con->y = 0; | 737 | con->pending.y = 0; |
692 | con->width = 0; | 738 | con->pending.width = 0; |
693 | con->height = 0; | 739 | con->pending.height = 0; |
694 | return; | 740 | return; |
695 | } | 741 | } |
696 | 742 | ||
697 | floating_natural_resize(con); | 743 | floating_natural_resize(con); |
698 | if (!con->view) { | 744 | if (!con->view) { |
699 | if (con->width > ws->width || con->height > ws->height) { | 745 | if (con->pending.width > ws->width || con->pending.height > ws->height) { |
700 | con->x = ob->x + (ob->width - con->width) / 2; | 746 | con->pending.x = ob->x + (ob->width - con->pending.width) / 2; |
701 | con->y = ob->y + (ob->height - con->height) / 2; | 747 | con->pending.y = ob->y + (ob->height - con->pending.height) / 2; |
702 | } else { | 748 | } else { |
703 | con->x = ws->x + (ws->width - con->width) / 2; | 749 | con->pending.x = ws->x + (ws->width - con->pending.width) / 2; |
704 | con->y = ws->y + (ws->height - con->height) / 2; | 750 | con->pending.y = ws->y + (ws->height - con->pending.height) / 2; |
705 | } | 751 | } |
706 | } else { | 752 | } else { |
707 | if (con->content_width > ws->width | 753 | if (con->pending.content_width > ws->width |
708 | || con->content_height > ws->height) { | 754 | || con->pending.content_height > ws->height) { |
709 | con->content_x = ob->x + (ob->width - con->content_width) / 2; | 755 | con->pending.content_x = ob->x + (ob->width - con->pending.content_width) / 2; |
710 | con->content_y = ob->y + (ob->height - con->content_height) / 2; | 756 | con->pending.content_y = ob->y + (ob->height - con->pending.content_height) / 2; |
711 | } else { | 757 | } else { |
712 | con->content_x = ws->x + (ws->width - con->content_width) / 2; | 758 | con->pending.content_x = ws->x + (ws->width - con->pending.content_width) / 2; |
713 | con->content_y = ws->y + (ws->height - con->content_height) / 2; | 759 | con->pending.content_y = ws->y + (ws->height - con->pending.content_height) / 2; |
714 | } | 760 | } |
715 | 761 | ||
716 | // If the view's border is B_NONE then these properties are ignored. | 762 | // If the view's border is B_NONE then these properties are ignored. |
717 | con->border_top = con->border_bottom = true; | 763 | con->pending.border_top = con->pending.border_bottom = true; |
718 | con->border_left = con->border_right = true; | 764 | con->pending.border_left = con->pending.border_right = true; |
719 | 765 | ||
720 | container_set_geometry_from_content(con); | 766 | container_set_geometry_from_content(con); |
721 | } | 767 | } |
722 | } | 768 | } |
723 | 769 | ||
724 | void container_floating_set_default_size(struct sway_container *con) { | 770 | void container_floating_set_default_size(struct sway_container *con) { |
725 | if (!sway_assert(con->workspace, "Expected a container on a workspace")) { | 771 | if (!sway_assert(con->pending.workspace, "Expected a container on a workspace")) { |
726 | return; | 772 | return; |
727 | } | 773 | } |
728 | 774 | ||
@@ -730,16 +776,16 @@ void container_floating_set_default_size(struct sway_container *con) { | |||
730 | floating_calculate_constraints(&min_width, &max_width, | 776 | floating_calculate_constraints(&min_width, &max_width, |
731 | &min_height, &max_height); | 777 | &min_height, &max_height); |
732 | struct wlr_box *box = calloc(1, sizeof(struct wlr_box)); | 778 | struct wlr_box *box = calloc(1, sizeof(struct wlr_box)); |
733 | workspace_get_box(con->workspace, box); | 779 | workspace_get_box(con->pending.workspace, box); |
734 | 780 | ||
735 | double width = fmax(min_width, fmin(box->width * 0.5, max_width)); | 781 | double width = fmax(min_width, fmin(box->width * 0.5, max_width)); |
736 | double height = fmax(min_height, fmin(box->height * 0.75, max_height)); | 782 | double height = fmax(min_height, fmin(box->height * 0.75, max_height)); |
737 | if (!con->view) { | 783 | if (!con->view) { |
738 | con->width = width; | 784 | con->pending.width = width; |
739 | con->height = height; | 785 | con->pending.height = height; |
740 | } else { | 786 | } else { |
741 | con->content_width = width; | 787 | con->pending.content_width = width; |
742 | con->content_height = height; | 788 | con->pending.content_height = height; |
743 | container_set_geometry_from_content(con); | 789 | container_set_geometry_from_content(con); |
744 | } | 790 | } |
745 | 791 | ||
@@ -761,8 +807,8 @@ void container_set_resizing(struct sway_container *con, bool resizing) { | |||
761 | con->view->impl->set_resizing(con->view, resizing); | 807 | con->view->impl->set_resizing(con->view, resizing); |
762 | } | 808 | } |
763 | } else { | 809 | } else { |
764 | for (int i = 0; i < con->children->length; ++i ) { | 810 | for (int i = 0; i < con->pending.children->length; ++i ) { |
765 | struct sway_container *child = con->children->items[i]; | 811 | struct sway_container *child = con->pending.children->items[i]; |
766 | container_set_resizing(child, resizing); | 812 | container_set_resizing(child, resizing); |
767 | } | 813 | } |
768 | } | 814 | } |
@@ -774,21 +820,33 @@ void container_set_floating(struct sway_container *container, bool enable) { | |||
774 | } | 820 | } |
775 | 821 | ||
776 | struct sway_seat *seat = input_manager_current_seat(); | 822 | struct sway_seat *seat = input_manager_current_seat(); |
777 | struct sway_workspace *workspace = container->workspace; | 823 | struct sway_workspace *workspace = container->pending.workspace; |
824 | struct sway_container *focus = seat_get_focused_container(seat); | ||
825 | bool set_focus = focus == container; | ||
778 | 826 | ||
779 | if (enable) { | 827 | if (enable) { |
780 | struct sway_container *old_parent = container->parent; | 828 | struct sway_container *old_parent = container->pending.parent; |
781 | container_detach(container); | 829 | container_detach(container); |
782 | workspace_add_floating(workspace, container); | 830 | workspace_add_floating(workspace, container); |
783 | if (container->view) { | 831 | if (container->view) { |
784 | view_set_tiled(container->view, false); | 832 | view_set_tiled(container->view, false); |
785 | if (container->view->using_csd) { | 833 | if (container->view->using_csd) { |
786 | container->border = B_CSD; | 834 | container->saved_border = container->pending.border; |
835 | container->pending.border = B_CSD; | ||
836 | if (container->view->xdg_decoration) { | ||
837 | struct sway_xdg_decoration *deco = container->view->xdg_decoration; | ||
838 | wlr_xdg_toplevel_decoration_v1_set_mode(deco->wlr_xdg_decoration, | ||
839 | WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE); | ||
840 | } | ||
787 | } | 841 | } |
788 | } | 842 | } |
789 | container_floating_set_default_size(container); | 843 | container_floating_set_default_size(container); |
790 | container_floating_resize_and_center(container); | 844 | container_floating_resize_and_center(container); |
791 | if (old_parent) { | 845 | if (old_parent) { |
846 | if (set_focus) { | ||
847 | seat_set_raw_focus(seat, &old_parent->node); | ||
848 | seat_set_raw_focus(seat, &container->node); | ||
849 | } | ||
792 | container_reap_empty(old_parent); | 850 | container_reap_empty(old_parent); |
793 | } | 851 | } |
794 | } else { | 852 | } else { |
@@ -800,19 +858,28 @@ void container_set_floating(struct sway_container *container, bool enable) { | |||
800 | struct sway_container *reference = | 858 | struct sway_container *reference = |
801 | seat_get_focus_inactive_tiling(seat, workspace); | 859 | seat_get_focus_inactive_tiling(seat, workspace); |
802 | if (reference) { | 860 | if (reference) { |
803 | container_add_sibling(reference, container, 1); | 861 | if (reference->view) { |
804 | container->width = reference->width; | 862 | container_add_sibling(reference, container, 1); |
805 | container->height = reference->height; | 863 | } else { |
864 | container_add_child(reference, container); | ||
865 | } | ||
866 | container->pending.width = reference->pending.width; | ||
867 | container->pending.height = reference->pending.height; | ||
806 | } else { | 868 | } else { |
807 | struct sway_container *other = | 869 | struct sway_container *other = |
808 | workspace_add_tiling(workspace, container); | 870 | workspace_add_tiling(workspace, container); |
809 | other->width = workspace->width; | 871 | other->pending.width = workspace->width; |
810 | other->height = workspace->height; | 872 | other->pending.height = workspace->height; |
811 | } | 873 | } |
812 | if (container->view) { | 874 | if (container->view) { |
813 | view_set_tiled(container->view, true); | 875 | view_set_tiled(container->view, true); |
814 | if (container->view->using_csd) { | 876 | if (container->view->using_csd) { |
815 | container->border = container->saved_border; | 877 | container->pending.border = container->saved_border; |
878 | if (container->view->xdg_decoration) { | ||
879 | struct sway_xdg_decoration *deco = container->view->xdg_decoration; | ||
880 | wlr_xdg_toplevel_decoration_v1_set_mode(deco->wlr_xdg_decoration, | ||
881 | WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); | ||
882 | } | ||
816 | } | 883 | } |
817 | } | 884 | } |
818 | container->width_fraction = 0; | 885 | container->width_fraction = 0; |
@@ -834,22 +901,33 @@ void container_set_geometry_from_content(struct sway_container *con) { | |||
834 | size_t border_width = 0; | 901 | size_t border_width = 0; |
835 | size_t top = 0; | 902 | size_t top = 0; |
836 | 903 | ||
837 | if (con->border != B_CSD) { | 904 | if (con->pending.border != B_CSD && !con->pending.fullscreen_mode) { |
838 | border_width = con->border_thickness * (con->border != B_NONE); | 905 | border_width = con->pending.border_thickness * (con->pending.border != B_NONE); |
839 | top = con->border == B_NORMAL ? | 906 | top = con->pending.border == B_NORMAL ? |
840 | container_titlebar_height() : border_width; | 907 | container_titlebar_height() : border_width; |
841 | } | 908 | } |
842 | 909 | ||
843 | con->x = con->content_x - border_width; | 910 | con->pending.x = con->pending.content_x - border_width; |
844 | con->y = con->content_y - top; | 911 | con->pending.y = con->pending.content_y - top; |
845 | con->width = con->content_width + border_width * 2; | 912 | con->pending.width = con->pending.content_width + border_width * 2; |
846 | con->height = top + con->content_height + border_width; | 913 | con->pending.height = top + con->pending.content_height + border_width; |
847 | node_set_dirty(&con->node); | 914 | node_set_dirty(&con->node); |
848 | } | 915 | } |
849 | 916 | ||
850 | bool container_is_floating(struct sway_container *container) { | 917 | bool container_is_floating(struct sway_container *container) { |
851 | if (!container->parent && container->workspace && | 918 | if (!container->pending.parent && container->pending.workspace && |
852 | list_find(container->workspace->floating, container) != -1) { | 919 | list_find(container->pending.workspace->floating, container) != -1) { |
920 | return true; | ||
921 | } | ||
922 | if (container->scratchpad) { | ||
923 | return true; | ||
924 | } | ||
925 | return false; | ||
926 | } | ||
927 | |||
928 | bool container_is_current_floating(struct sway_container *container) { | ||
929 | if (!container->current.parent && container->current.workspace && | ||
930 | list_find(container->current.workspace->floating, container) != -1) { | ||
853 | return true; | 931 | return true; |
854 | } | 932 | } |
855 | if (container->scratchpad) { | 933 | if (container->scratchpad) { |
@@ -859,10 +937,10 @@ bool container_is_floating(struct sway_container *container) { | |||
859 | } | 937 | } |
860 | 938 | ||
861 | void container_get_box(struct sway_container *container, struct wlr_box *box) { | 939 | void container_get_box(struct sway_container *container, struct wlr_box *box) { |
862 | box->x = container->x; | 940 | box->x = container->pending.x; |
863 | box->y = container->y; | 941 | box->y = container->pending.y; |
864 | box->width = container->width; | 942 | box->width = container->pending.width; |
865 | box->height = container->height; | 943 | box->height = container->pending.height; |
866 | } | 944 | } |
867 | 945 | ||
868 | /** | 946 | /** |
@@ -870,14 +948,14 @@ void container_get_box(struct sway_container *container, struct wlr_box *box) { | |||
870 | */ | 948 | */ |
871 | void container_floating_translate(struct sway_container *con, | 949 | void container_floating_translate(struct sway_container *con, |
872 | double x_amount, double y_amount) { | 950 | double x_amount, double y_amount) { |
873 | con->x += x_amount; | 951 | con->pending.x += x_amount; |
874 | con->y += y_amount; | 952 | con->pending.y += y_amount; |
875 | con->content_x += x_amount; | 953 | con->pending.content_x += x_amount; |
876 | con->content_y += y_amount; | 954 | con->pending.content_y += y_amount; |
877 | 955 | ||
878 | if (con->children) { | 956 | if (con->pending.children) { |
879 | for (int i = 0; i < con->children->length; ++i) { | 957 | for (int i = 0; i < con->pending.children->length; ++i) { |
880 | struct sway_container *child = con->children->items[i]; | 958 | struct sway_container *child = con->pending.children->items[i]; |
881 | container_floating_translate(child, x_amount, y_amount); | 959 | container_floating_translate(child, x_amount, y_amount); |
882 | } | 960 | } |
883 | } | 961 | } |
@@ -893,8 +971,8 @@ void container_floating_translate(struct sway_container *con, | |||
893 | * center. | 971 | * center. |
894 | */ | 972 | */ |
895 | struct sway_output *container_floating_find_output(struct sway_container *con) { | 973 | struct sway_output *container_floating_find_output(struct sway_container *con) { |
896 | double center_x = con->x + con->width / 2; | 974 | double center_x = con->pending.x + con->pending.width / 2; |
897 | double center_y = con->y + con->height / 2; | 975 | double center_y = con->pending.y + con->pending.height / 2; |
898 | struct sway_output *closest_output = NULL; | 976 | struct sway_output *closest_output = NULL; |
899 | double closest_distance = DBL_MAX; | 977 | double closest_distance = DBL_MAX; |
900 | for (int i = 0; i < root->outputs->length; ++i) { | 978 | for (int i = 0; i < root->outputs->length; ++i) { |
@@ -925,11 +1003,11 @@ void container_floating_move_to(struct sway_container *con, | |||
925 | "Expected a floating container")) { | 1003 | "Expected a floating container")) { |
926 | return; | 1004 | return; |
927 | } | 1005 | } |
928 | container_floating_translate(con, lx - con->x, ly - con->y); | 1006 | container_floating_translate(con, lx - con->pending.x, ly - con->pending.y); |
929 | if (container_is_scratchpad_hidden(con)) { | 1007 | if (container_is_scratchpad_hidden(con)) { |
930 | return; | 1008 | return; |
931 | } | 1009 | } |
932 | struct sway_workspace *old_workspace = con->workspace; | 1010 | struct sway_workspace *old_workspace = con->pending.workspace; |
933 | struct sway_output *new_output = container_floating_find_output(con); | 1011 | struct sway_output *new_output = container_floating_find_output(con); |
934 | if (!sway_assert(new_output, "Unable to find any output")) { | 1012 | if (!sway_assert(new_output, "Unable to find any output")) { |
935 | return; | 1013 | return; |
@@ -951,10 +1029,10 @@ void container_floating_move_to_center(struct sway_container *con) { | |||
951 | "Expected a floating container")) { | 1029 | "Expected a floating container")) { |
952 | return; | 1030 | return; |
953 | } | 1031 | } |
954 | struct sway_workspace *ws = con->workspace; | 1032 | struct sway_workspace *ws = con->pending.workspace; |
955 | double new_lx = ws->x + (ws->width - con->width) / 2; | 1033 | double new_lx = ws->x + (ws->width - con->pending.width) / 2; |
956 | double new_ly = ws->y + (ws->height - con->height) / 2; | 1034 | double new_ly = ws->y + (ws->height - con->pending.height) / 2; |
957 | container_floating_translate(con, new_lx - con->x, new_ly - con->y); | 1035 | container_floating_translate(con, new_lx - con->pending.x, new_ly - con->pending.y); |
958 | } | 1036 | } |
959 | 1037 | ||
960 | static bool find_urgent_iterator(struct sway_container *con, void *data) { | 1038 | static bool find_urgent_iterator(struct sway_container *con, void *data) { |
@@ -972,42 +1050,39 @@ void container_end_mouse_operation(struct sway_container *container) { | |||
972 | } | 1050 | } |
973 | } | 1051 | } |
974 | 1052 | ||
975 | static void set_fullscreen_iterator(struct sway_container *con, void *data) { | 1053 | static void set_fullscreen(struct sway_container *con, bool enable) { |
976 | if (!con->view) { | 1054 | if (!con->view) { |
977 | return; | 1055 | return; |
978 | } | 1056 | } |
979 | if (con->view->impl->set_fullscreen) { | 1057 | if (con->view->impl->set_fullscreen) { |
980 | bool *enable = data; | 1058 | con->view->impl->set_fullscreen(con->view, enable); |
981 | con->view->impl->set_fullscreen(con->view, *enable); | ||
982 | if (con->view->foreign_toplevel) { | 1059 | if (con->view->foreign_toplevel) { |
983 | wlr_foreign_toplevel_handle_v1_set_fullscreen( | 1060 | wlr_foreign_toplevel_handle_v1_set_fullscreen( |
984 | con->view->foreign_toplevel, *enable); | 1061 | con->view->foreign_toplevel, enable); |
985 | } | 1062 | } |
986 | } | 1063 | } |
987 | } | 1064 | } |
988 | 1065 | ||
989 | static void container_fullscreen_workspace(struct sway_container *con) { | 1066 | static void container_fullscreen_workspace(struct sway_container *con) { |
990 | if (!sway_assert(con->fullscreen_mode == FULLSCREEN_NONE, | 1067 | if (!sway_assert(con->pending.fullscreen_mode == FULLSCREEN_NONE, |
991 | "Expected a non-fullscreen container")) { | 1068 | "Expected a non-fullscreen container")) { |
992 | return; | 1069 | return; |
993 | } | 1070 | } |
994 | bool enable = true; | 1071 | set_fullscreen(con, true); |
995 | set_fullscreen_iterator(con, &enable); | 1072 | con->pending.fullscreen_mode = FULLSCREEN_WORKSPACE; |
996 | container_for_each_child(con, set_fullscreen_iterator, &enable); | ||
997 | con->fullscreen_mode = FULLSCREEN_WORKSPACE; | ||
998 | 1073 | ||
999 | con->saved_x = con->x; | 1074 | con->saved_x = con->pending.x; |
1000 | con->saved_y = con->y; | 1075 | con->saved_y = con->pending.y; |
1001 | con->saved_width = con->width; | 1076 | con->saved_width = con->pending.width; |
1002 | con->saved_height = con->height; | 1077 | con->saved_height = con->pending.height; |
1003 | 1078 | ||
1004 | if (con->workspace) { | 1079 | if (con->pending.workspace) { |
1005 | con->workspace->fullscreen = con; | 1080 | con->pending.workspace->fullscreen = con; |
1006 | struct sway_seat *seat; | 1081 | struct sway_seat *seat; |
1007 | struct sway_workspace *focus_ws; | 1082 | struct sway_workspace *focus_ws; |
1008 | wl_list_for_each(seat, &server.input->seats, link) { | 1083 | wl_list_for_each(seat, &server.input->seats, link) { |
1009 | focus_ws = seat_get_focused_workspace(seat); | 1084 | focus_ws = seat_get_focused_workspace(seat); |
1010 | if (focus_ws == con->workspace) { | 1085 | if (focus_ws == con->pending.workspace) { |
1011 | seat_set_focus_container(seat, con); | 1086 | seat_set_focus_container(seat, con); |
1012 | } else { | 1087 | } else { |
1013 | struct sway_node *focus = | 1088 | struct sway_node *focus = |
@@ -1023,19 +1098,17 @@ static void container_fullscreen_workspace(struct sway_container *con) { | |||
1023 | } | 1098 | } |
1024 | 1099 | ||
1025 | static void container_fullscreen_global(struct sway_container *con) { | 1100 | static void container_fullscreen_global(struct sway_container *con) { |
1026 | if (!sway_assert(con->fullscreen_mode == FULLSCREEN_NONE, | 1101 | if (!sway_assert(con->pending.fullscreen_mode == FULLSCREEN_NONE, |
1027 | "Expected a non-fullscreen container")) { | 1102 | "Expected a non-fullscreen container")) { |
1028 | return; | 1103 | return; |
1029 | } | 1104 | } |
1030 | bool enable = true; | 1105 | set_fullscreen(con, true); |
1031 | set_fullscreen_iterator(con, &enable); | ||
1032 | container_for_each_child(con, set_fullscreen_iterator, &enable); | ||
1033 | 1106 | ||
1034 | root->fullscreen_global = con; | 1107 | root->fullscreen_global = con; |
1035 | con->saved_x = con->x; | 1108 | con->saved_x = con->pending.x; |
1036 | con->saved_y = con->y; | 1109 | con->saved_y = con->pending.y; |
1037 | con->saved_width = con->width; | 1110 | con->saved_width = con->pending.width; |
1038 | con->saved_height = con->height; | 1111 | con->saved_height = con->pending.height; |
1039 | 1112 | ||
1040 | struct sway_seat *seat; | 1113 | struct sway_seat *seat; |
1041 | wl_list_for_each(seat, &server.input->seats, link) { | 1114 | wl_list_for_each(seat, &server.input->seats, link) { |
@@ -1045,34 +1118,32 @@ static void container_fullscreen_global(struct sway_container *con) { | |||
1045 | } | 1118 | } |
1046 | } | 1119 | } |
1047 | 1120 | ||
1048 | con->fullscreen_mode = FULLSCREEN_GLOBAL; | 1121 | con->pending.fullscreen_mode = FULLSCREEN_GLOBAL; |
1049 | container_end_mouse_operation(con); | 1122 | container_end_mouse_operation(con); |
1050 | ipc_event_window(con, "fullscreen_mode"); | 1123 | ipc_event_window(con, "fullscreen_mode"); |
1051 | } | 1124 | } |
1052 | 1125 | ||
1053 | void container_fullscreen_disable(struct sway_container *con) { | 1126 | void container_fullscreen_disable(struct sway_container *con) { |
1054 | if (!sway_assert(con->fullscreen_mode != FULLSCREEN_NONE, | 1127 | if (!sway_assert(con->pending.fullscreen_mode != FULLSCREEN_NONE, |
1055 | "Expected a fullscreen container")) { | 1128 | "Expected a fullscreen container")) { |
1056 | return; | 1129 | return; |
1057 | } | 1130 | } |
1058 | bool enable = false; | 1131 | set_fullscreen(con, false); |
1059 | set_fullscreen_iterator(con, &enable); | ||
1060 | container_for_each_child(con, set_fullscreen_iterator, &enable); | ||
1061 | 1132 | ||
1062 | if (container_is_floating(con)) { | 1133 | if (container_is_floating(con)) { |
1063 | con->x = con->saved_x; | 1134 | con->pending.x = con->saved_x; |
1064 | con->y = con->saved_y; | 1135 | con->pending.y = con->saved_y; |
1065 | con->width = con->saved_width; | 1136 | con->pending.width = con->saved_width; |
1066 | con->height = con->saved_height; | 1137 | con->pending.height = con->saved_height; |
1067 | } | 1138 | } |
1068 | 1139 | ||
1069 | if (con->fullscreen_mode == FULLSCREEN_WORKSPACE) { | 1140 | if (con->pending.fullscreen_mode == FULLSCREEN_WORKSPACE) { |
1070 | if (con->workspace) { | 1141 | if (con->pending.workspace) { |
1071 | con->workspace->fullscreen = NULL; | 1142 | con->pending.workspace->fullscreen = NULL; |
1072 | if (container_is_floating(con)) { | 1143 | if (container_is_floating(con)) { |
1073 | struct sway_output *output = | 1144 | struct sway_output *output = |
1074 | container_floating_find_output(con); | 1145 | container_floating_find_output(con); |
1075 | if (con->workspace->output != output) { | 1146 | if (con->pending.workspace->output != output) { |
1076 | container_floating_move_to_center(con); | 1147 | container_floating_move_to_center(con); |
1077 | } | 1148 | } |
1078 | } | 1149 | } |
@@ -1084,11 +1155,11 @@ void container_fullscreen_disable(struct sway_container *con) { | |||
1084 | // If the container was mapped as fullscreen and set as floating by | 1155 | // If the container was mapped as fullscreen and set as floating by |
1085 | // criteria, it needs to be reinitialized as floating to get the proper | 1156 | // criteria, it needs to be reinitialized as floating to get the proper |
1086 | // size and location | 1157 | // size and location |
1087 | if (container_is_floating(con) && (con->width == 0 || con->height == 0)) { | 1158 | if (container_is_floating(con) && (con->pending.width == 0 || con->pending.height == 0)) { |
1088 | container_floating_resize_and_center(con); | 1159 | container_floating_resize_and_center(con); |
1089 | } | 1160 | } |
1090 | 1161 | ||
1091 | con->fullscreen_mode = FULLSCREEN_NONE; | 1162 | con->pending.fullscreen_mode = FULLSCREEN_NONE; |
1092 | container_end_mouse_operation(con); | 1163 | container_end_mouse_operation(con); |
1093 | ipc_event_window(con, "fullscreen_mode"); | 1164 | ipc_event_window(con, "fullscreen_mode"); |
1094 | 1165 | ||
@@ -1106,7 +1177,7 @@ void container_fullscreen_disable(struct sway_container *con) { | |||
1106 | 1177 | ||
1107 | void container_set_fullscreen(struct sway_container *con, | 1178 | void container_set_fullscreen(struct sway_container *con, |
1108 | enum sway_fullscreen_mode mode) { | 1179 | enum sway_fullscreen_mode mode) { |
1109 | if (con->fullscreen_mode == mode) { | 1180 | if (con->pending.fullscreen_mode == mode) { |
1110 | return; | 1181 | return; |
1111 | } | 1182 | } |
1112 | 1183 | ||
@@ -1118,8 +1189,8 @@ void container_set_fullscreen(struct sway_container *con, | |||
1118 | if (root->fullscreen_global) { | 1189 | if (root->fullscreen_global) { |
1119 | container_fullscreen_disable(root->fullscreen_global); | 1190 | container_fullscreen_disable(root->fullscreen_global); |
1120 | } | 1191 | } |
1121 | if (con->workspace && con->workspace->fullscreen) { | 1192 | if (con->pending.workspace && con->pending.workspace->fullscreen) { |
1122 | container_fullscreen_disable(con->workspace->fullscreen); | 1193 | container_fullscreen_disable(con->pending.workspace->fullscreen); |
1123 | } | 1194 | } |
1124 | container_fullscreen_workspace(con); | 1195 | container_fullscreen_workspace(con); |
1125 | break; | 1196 | break; |
@@ -1127,7 +1198,7 @@ void container_set_fullscreen(struct sway_container *con, | |||
1127 | if (root->fullscreen_global) { | 1198 | if (root->fullscreen_global) { |
1128 | container_fullscreen_disable(root->fullscreen_global); | 1199 | container_fullscreen_disable(root->fullscreen_global); |
1129 | } | 1200 | } |
1130 | if (con->fullscreen_mode == FULLSCREEN_WORKSPACE) { | 1201 | if (con->pending.fullscreen_mode == FULLSCREEN_WORKSPACE) { |
1131 | container_fullscreen_disable(con); | 1202 | container_fullscreen_disable(con); |
1132 | } | 1203 | } |
1133 | container_fullscreen_global(con); | 1204 | container_fullscreen_global(con); |
@@ -1137,8 +1208,8 @@ void container_set_fullscreen(struct sway_container *con, | |||
1137 | 1208 | ||
1138 | struct sway_container *container_toplevel_ancestor( | 1209 | struct sway_container *container_toplevel_ancestor( |
1139 | struct sway_container *container) { | 1210 | struct sway_container *container) { |
1140 | while (container->parent) { | 1211 | while (container->pending.parent) { |
1141 | container = container->parent; | 1212 | container = container->pending.parent; |
1142 | } | 1213 | } |
1143 | 1214 | ||
1144 | return container; | 1215 | return container; |
@@ -1150,10 +1221,10 @@ bool container_is_floating_or_child(struct sway_container *container) { | |||
1150 | 1221 | ||
1151 | bool container_is_fullscreen_or_child(struct sway_container *container) { | 1222 | bool container_is_fullscreen_or_child(struct sway_container *container) { |
1152 | do { | 1223 | do { |
1153 | if (container->fullscreen_mode) { | 1224 | if (container->pending.fullscreen_mode) { |
1154 | return true; | 1225 | return true; |
1155 | } | 1226 | } |
1156 | container = container->parent; | 1227 | container = container->pending.parent; |
1157 | } while (container); | 1228 | } while (container); |
1158 | 1229 | ||
1159 | return false; | 1230 | return false; |
@@ -1226,11 +1297,11 @@ void container_discover_outputs(struct sway_container *con) { | |||
1226 | } | 1297 | } |
1227 | 1298 | ||
1228 | enum sway_container_layout container_parent_layout(struct sway_container *con) { | 1299 | enum sway_container_layout container_parent_layout(struct sway_container *con) { |
1229 | if (con->parent) { | 1300 | if (con->pending.parent) { |
1230 | return con->parent->layout; | 1301 | return con->pending.parent->pending.layout; |
1231 | } | 1302 | } |
1232 | if (con->workspace) { | 1303 | if (con->pending.workspace) { |
1233 | return con->workspace->layout; | 1304 | return con->pending.workspace->layout; |
1234 | } | 1305 | } |
1235 | return L_NONE; | 1306 | return L_NONE; |
1236 | } | 1307 | } |
@@ -1244,16 +1315,16 @@ enum sway_container_layout container_current_parent_layout( | |||
1244 | } | 1315 | } |
1245 | 1316 | ||
1246 | list_t *container_get_siblings(struct sway_container *container) { | 1317 | list_t *container_get_siblings(struct sway_container *container) { |
1247 | if (container->parent) { | 1318 | if (container->pending.parent) { |
1248 | return container->parent->children; | 1319 | return container->pending.parent->pending.children; |
1249 | } | 1320 | } |
1250 | if (container_is_scratchpad_hidden(container)) { | 1321 | if (container_is_scratchpad_hidden(container)) { |
1251 | return NULL; | 1322 | return NULL; |
1252 | } | 1323 | } |
1253 | if (list_find(container->workspace->tiling, container) != -1) { | 1324 | if (list_find(container->pending.workspace->tiling, container) != -1) { |
1254 | return container->workspace->tiling; | 1325 | return container->pending.workspace->tiling; |
1255 | } | 1326 | } |
1256 | return container->workspace->floating; | 1327 | return container->pending.workspace->floating; |
1257 | } | 1328 | } |
1258 | 1329 | ||
1259 | int container_sibling_index(struct sway_container *child) { | 1330 | int container_sibling_index(struct sway_container *child) { |
@@ -1268,30 +1339,30 @@ list_t *container_get_current_siblings(struct sway_container *container) { | |||
1268 | } | 1339 | } |
1269 | 1340 | ||
1270 | void container_handle_fullscreen_reparent(struct sway_container *con) { | 1341 | void container_handle_fullscreen_reparent(struct sway_container *con) { |
1271 | if (con->fullscreen_mode != FULLSCREEN_WORKSPACE || !con->workspace || | 1342 | if (con->pending.fullscreen_mode != FULLSCREEN_WORKSPACE || !con->pending.workspace || |
1272 | con->workspace->fullscreen == con) { | 1343 | con->pending.workspace->fullscreen == con) { |
1273 | return; | 1344 | return; |
1274 | } | 1345 | } |
1275 | if (con->workspace->fullscreen) { | 1346 | if (con->pending.workspace->fullscreen) { |
1276 | container_fullscreen_disable(con->workspace->fullscreen); | 1347 | container_fullscreen_disable(con->pending.workspace->fullscreen); |
1277 | } | 1348 | } |
1278 | con->workspace->fullscreen = con; | 1349 | con->pending.workspace->fullscreen = con; |
1279 | 1350 | ||
1280 | arrange_workspace(con->workspace); | 1351 | arrange_workspace(con->pending.workspace); |
1281 | } | 1352 | } |
1282 | 1353 | ||
1283 | static void set_workspace(struct sway_container *container, void *data) { | 1354 | static void set_workspace(struct sway_container *container, void *data) { |
1284 | container->workspace = container->parent->workspace; | 1355 | container->pending.workspace = container->pending.parent->pending.workspace; |
1285 | } | 1356 | } |
1286 | 1357 | ||
1287 | void container_insert_child(struct sway_container *parent, | 1358 | void container_insert_child(struct sway_container *parent, |
1288 | struct sway_container *child, int i) { | 1359 | struct sway_container *child, int i) { |
1289 | if (child->workspace) { | 1360 | if (child->pending.workspace) { |
1290 | container_detach(child); | 1361 | container_detach(child); |
1291 | } | 1362 | } |
1292 | list_insert(parent->children, i, child); | 1363 | list_insert(parent->pending.children, i, child); |
1293 | child->parent = parent; | 1364 | child->pending.parent = parent; |
1294 | child->workspace = parent->workspace; | 1365 | child->pending.workspace = parent->pending.workspace; |
1295 | container_for_each_child(child, set_workspace, NULL); | 1366 | container_for_each_child(child, set_workspace, NULL); |
1296 | container_handle_fullscreen_reparent(child); | 1367 | container_handle_fullscreen_reparent(child); |
1297 | container_update_representation(parent); | 1368 | container_update_representation(parent); |
@@ -1299,14 +1370,14 @@ void container_insert_child(struct sway_container *parent, | |||
1299 | 1370 | ||
1300 | void container_add_sibling(struct sway_container *fixed, | 1371 | void container_add_sibling(struct sway_container *fixed, |
1301 | struct sway_container *active, bool after) { | 1372 | struct sway_container *active, bool after) { |
1302 | if (active->workspace) { | 1373 | if (active->pending.workspace) { |
1303 | container_detach(active); | 1374 | container_detach(active); |
1304 | } | 1375 | } |
1305 | list_t *siblings = container_get_siblings(fixed); | 1376 | list_t *siblings = container_get_siblings(fixed); |
1306 | int index = list_find(siblings, fixed); | 1377 | int index = list_find(siblings, fixed); |
1307 | list_insert(siblings, index + after, active); | 1378 | list_insert(siblings, index + after, active); |
1308 | active->parent = fixed->parent; | 1379 | active->pending.parent = fixed->pending.parent; |
1309 | active->workspace = fixed->workspace; | 1380 | active->pending.workspace = fixed->pending.workspace; |
1310 | container_for_each_child(active, set_workspace, NULL); | 1381 | container_for_each_child(active, set_workspace, NULL); |
1311 | container_handle_fullscreen_reparent(active); | 1382 | container_handle_fullscreen_reparent(active); |
1312 | container_update_representation(active); | 1383 | container_update_representation(active); |
@@ -1314,17 +1385,13 @@ void container_add_sibling(struct sway_container *fixed, | |||
1314 | 1385 | ||
1315 | void container_add_child(struct sway_container *parent, | 1386 | void container_add_child(struct sway_container *parent, |
1316 | struct sway_container *child) { | 1387 | struct sway_container *child) { |
1317 | if (child->workspace) { | 1388 | if (child->pending.workspace) { |
1318 | container_detach(child); | 1389 | container_detach(child); |
1319 | } | 1390 | } |
1320 | list_add(parent->children, child); | 1391 | list_add(parent->pending.children, child); |
1321 | child->parent = parent; | 1392 | child->pending.parent = parent; |
1322 | child->workspace = parent->workspace; | 1393 | child->pending.workspace = parent->pending.workspace; |
1323 | container_for_each_child(child, set_workspace, NULL); | 1394 | container_for_each_child(child, set_workspace, NULL); |
1324 | bool fullscreen = child->fullscreen_mode != FULLSCREEN_NONE || | ||
1325 | parent->fullscreen_mode != FULLSCREEN_NONE; | ||
1326 | set_fullscreen_iterator(child, &fullscreen); | ||
1327 | container_for_each_child(child, set_fullscreen_iterator, &fullscreen); | ||
1328 | container_handle_fullscreen_reparent(child); | 1395 | container_handle_fullscreen_reparent(child); |
1329 | container_update_representation(parent); | 1396 | container_update_representation(parent); |
1330 | node_set_dirty(&child->node); | 1397 | node_set_dirty(&child->node); |
@@ -1332,15 +1399,15 @@ void container_add_child(struct sway_container *parent, | |||
1332 | } | 1399 | } |
1333 | 1400 | ||
1334 | void container_detach(struct sway_container *child) { | 1401 | void container_detach(struct sway_container *child) { |
1335 | if (child->fullscreen_mode == FULLSCREEN_WORKSPACE) { | 1402 | if (child->pending.fullscreen_mode == FULLSCREEN_WORKSPACE) { |
1336 | child->workspace->fullscreen = NULL; | 1403 | child->pending.workspace->fullscreen = NULL; |
1337 | } | 1404 | } |
1338 | if (child->fullscreen_mode == FULLSCREEN_GLOBAL) { | 1405 | if (child->pending.fullscreen_mode == FULLSCREEN_GLOBAL) { |
1339 | root->fullscreen_global = NULL; | 1406 | root->fullscreen_global = NULL; |
1340 | } | 1407 | } |
1341 | 1408 | ||
1342 | struct sway_container *old_parent = child->parent; | 1409 | struct sway_container *old_parent = child->pending.parent; |
1343 | struct sway_workspace *old_workspace = child->workspace; | 1410 | struct sway_workspace *old_workspace = child->pending.workspace; |
1344 | list_t *siblings = container_get_siblings(child); | 1411 | list_t *siblings = container_get_siblings(child); |
1345 | if (siblings) { | 1412 | if (siblings) { |
1346 | int index = list_find(siblings, child); | 1413 | int index = list_find(siblings, child); |
@@ -1348,8 +1415,8 @@ void container_detach(struct sway_container *child) { | |||
1348 | list_del(siblings, index); | 1415 | list_del(siblings, index); |
1349 | } | 1416 | } |
1350 | } | 1417 | } |
1351 | child->parent = NULL; | 1418 | child->pending.parent = NULL; |
1352 | child->workspace = NULL; | 1419 | child->pending.workspace = NULL; |
1353 | container_for_each_child(child, set_workspace, NULL); | 1420 | container_for_each_child(child, set_workspace, NULL); |
1354 | 1421 | ||
1355 | if (old_parent) { | 1422 | if (old_parent) { |
@@ -1364,18 +1431,18 @@ void container_detach(struct sway_container *child) { | |||
1364 | 1431 | ||
1365 | void container_replace(struct sway_container *container, | 1432 | void container_replace(struct sway_container *container, |
1366 | struct sway_container *replacement) { | 1433 | struct sway_container *replacement) { |
1367 | enum sway_fullscreen_mode fullscreen = container->fullscreen_mode; | 1434 | enum sway_fullscreen_mode fullscreen = container->pending.fullscreen_mode; |
1368 | bool scratchpad = container->scratchpad; | 1435 | bool scratchpad = container->scratchpad; |
1369 | struct sway_workspace *ws = NULL; | 1436 | struct sway_workspace *ws = NULL; |
1370 | if (fullscreen != FULLSCREEN_NONE) { | 1437 | if (fullscreen != FULLSCREEN_NONE) { |
1371 | container_fullscreen_disable(container); | 1438 | container_fullscreen_disable(container); |
1372 | } | 1439 | } |
1373 | if (scratchpad) { | 1440 | if (scratchpad) { |
1374 | ws = container->workspace; | 1441 | ws = container->pending.workspace; |
1375 | root_scratchpad_show(container); | 1442 | root_scratchpad_show(container); |
1376 | root_scratchpad_remove_container(container); | 1443 | root_scratchpad_remove_container(container); |
1377 | } | 1444 | } |
1378 | if (container->parent || container->workspace) { | 1445 | if (container->pending.parent || container->pending.workspace) { |
1379 | float width_fraction = container->width_fraction; | 1446 | float width_fraction = container->width_fraction; |
1380 | float height_fraction = container->height_fraction; | 1447 | float height_fraction = container->height_fraction; |
1381 | container_add_sibling(container, replacement, 1); | 1448 | container_add_sibling(container, replacement, 1); |
@@ -1403,7 +1470,7 @@ struct sway_container *container_split(struct sway_container *child, | |||
1403 | enum sway_container_layout layout) { | 1470 | enum sway_container_layout layout) { |
1404 | // i3 doesn't split singleton H/V containers | 1471 | // i3 doesn't split singleton H/V containers |
1405 | // https://github.com/i3/i3/blob/3cd1c45eba6de073bc4300eebb4e1cc1a0c4479a/src/tree.c#L354 | 1472 | // https://github.com/i3/i3/blob/3cd1c45eba6de073bc4300eebb4e1cc1a0c4479a/src/tree.c#L354 |
1406 | if (child->parent || child->workspace) { | 1473 | if (child->pending.parent || child->pending.workspace) { |
1407 | list_t *siblings = container_get_siblings(child); | 1474 | list_t *siblings = container_get_siblings(child); |
1408 | if (siblings->length == 1) { | 1475 | if (siblings->length == 1) { |
1409 | enum sway_container_layout current = container_parent_layout(child); | 1476 | enum sway_container_layout current = container_parent_layout(child); |
@@ -1411,12 +1478,12 @@ struct sway_container *container_split(struct sway_container *child, | |||
1411 | current = L_NONE; | 1478 | current = L_NONE; |
1412 | } | 1479 | } |
1413 | if (current == L_HORIZ || current == L_VERT) { | 1480 | if (current == L_HORIZ || current == L_VERT) { |
1414 | if (child->parent) { | 1481 | if (child->pending.parent) { |
1415 | child->parent->layout = layout; | 1482 | child->pending.parent->pending.layout = layout; |
1416 | container_update_representation(child->parent); | 1483 | container_update_representation(child->pending.parent); |
1417 | } else { | 1484 | } else { |
1418 | child->workspace->layout = layout; | 1485 | child->pending.workspace->layout = layout; |
1419 | workspace_update_representation(child->workspace); | 1486 | workspace_update_representation(child->pending.workspace); |
1420 | } | 1487 | } |
1421 | return child; | 1488 | return child; |
1422 | } | 1489 | } |
@@ -1429,25 +1496,25 @@ struct sway_container *container_split(struct sway_container *child, | |||
1429 | if (container_is_floating(child) && child->view) { | 1496 | if (container_is_floating(child) && child->view) { |
1430 | view_set_tiled(child->view, true); | 1497 | view_set_tiled(child->view, true); |
1431 | if (child->view->using_csd) { | 1498 | if (child->view->using_csd) { |
1432 | child->border = child->saved_border; | 1499 | child->pending.border = child->saved_border; |
1433 | } | 1500 | } |
1434 | } | 1501 | } |
1435 | 1502 | ||
1436 | struct sway_container *cont = container_create(NULL); | 1503 | struct sway_container *cont = container_create(NULL); |
1437 | cont->width = child->width; | 1504 | cont->pending.width = child->pending.width; |
1438 | cont->height = child->height; | 1505 | cont->pending.height = child->pending.height; |
1439 | cont->width_fraction = child->width_fraction; | 1506 | cont->width_fraction = child->width_fraction; |
1440 | cont->height_fraction = child->height_fraction; | 1507 | cont->height_fraction = child->height_fraction; |
1441 | cont->x = child->x; | 1508 | cont->pending.x = child->pending.x; |
1442 | cont->y = child->y; | 1509 | cont->pending.y = child->pending.y; |
1443 | cont->layout = layout; | 1510 | cont->pending.layout = layout; |
1444 | 1511 | ||
1445 | container_replace(child, cont); | 1512 | container_replace(child, cont); |
1446 | container_add_child(cont, child); | 1513 | container_add_child(cont, child); |
1447 | 1514 | ||
1448 | if (set_focus) { | 1515 | if (set_focus) { |
1449 | seat_set_raw_focus(seat, &cont->node); | 1516 | seat_set_raw_focus(seat, &cont->node); |
1450 | if (cont->fullscreen_mode == FULLSCREEN_GLOBAL) { | 1517 | if (cont->pending.fullscreen_mode == FULLSCREEN_GLOBAL) { |
1451 | seat_set_focus(seat, &child->node); | 1518 | seat_set_focus(seat, &child->node); |
1452 | } else { | 1519 | } else { |
1453 | seat_set_raw_focus(seat, &child->node); | 1520 | seat_set_raw_focus(seat, &child->node); |
@@ -1554,39 +1621,8 @@ static void update_marks_texture(struct sway_container *con, | |||
1554 | } | 1621 | } |
1555 | free(part); | 1622 | free(part); |
1556 | 1623 | ||
1557 | double scale = output->wlr_output->scale; | 1624 | render_titlebar_text_texture(output, con, texture, class, false, buffer); |
1558 | int width = 0; | ||
1559 | int height = con->title_height * scale; | ||
1560 | |||
1561 | cairo_t *c = cairo_create(NULL); | ||
1562 | get_text_size(c, config->font, &width, NULL, NULL, scale, false, | ||
1563 | "%s", buffer); | ||
1564 | cairo_destroy(c); | ||
1565 | 1625 | ||
1566 | cairo_surface_t *surface = cairo_image_surface_create( | ||
1567 | CAIRO_FORMAT_ARGB32, width, height); | ||
1568 | cairo_t *cairo = cairo_create(surface); | ||
1569 | cairo_set_source_rgba(cairo, class->background[0], class->background[1], | ||
1570 | class->background[2], class->background[3]); | ||
1571 | cairo_paint(cairo); | ||
1572 | PangoContext *pango = pango_cairo_create_context(cairo); | ||
1573 | cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); | ||
1574 | cairo_set_source_rgba(cairo, class->text[0], class->text[1], | ||
1575 | class->text[2], class->text[3]); | ||
1576 | cairo_move_to(cairo, 0, 0); | ||
1577 | |||
1578 | pango_printf(cairo, config->font, scale, false, "%s", buffer); | ||
1579 | |||
1580 | cairo_surface_flush(surface); | ||
1581 | unsigned char *data = cairo_image_surface_get_data(surface); | ||
1582 | int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width); | ||
1583 | struct wlr_renderer *renderer = wlr_backend_get_renderer( | ||
1584 | output->wlr_output->backend); | ||
1585 | *texture = wlr_texture_from_pixels( | ||
1586 | renderer, WL_SHM_FORMAT_ARGB8888, stride, width, height, data); | ||
1587 | cairo_surface_destroy(surface); | ||
1588 | g_object_unref(pango); | ||
1589 | cairo_destroy(cairo); | ||
1590 | free(buffer); | 1626 | free(buffer); |
1591 | } | 1627 | } |
1592 | 1628 | ||
@@ -1608,19 +1644,19 @@ void container_update_marks_textures(struct sway_container *con) { | |||
1608 | void container_raise_floating(struct sway_container *con) { | 1644 | void container_raise_floating(struct sway_container *con) { |
1609 | // Bring container to front by putting it at the end of the floating list. | 1645 | // Bring container to front by putting it at the end of the floating list. |
1610 | struct sway_container *floater = container_toplevel_ancestor(con); | 1646 | struct sway_container *floater = container_toplevel_ancestor(con); |
1611 | if (container_is_floating(floater) && floater->workspace) { | 1647 | if (container_is_floating(floater) && floater->pending.workspace) { |
1612 | list_move_to_end(floater->workspace->floating, floater); | 1648 | list_move_to_end(floater->pending.workspace->floating, floater); |
1613 | node_set_dirty(&floater->workspace->node); | 1649 | node_set_dirty(&floater->pending.workspace->node); |
1614 | } | 1650 | } |
1615 | } | 1651 | } |
1616 | 1652 | ||
1617 | bool container_is_scratchpad_hidden(struct sway_container *con) { | 1653 | bool container_is_scratchpad_hidden(struct sway_container *con) { |
1618 | return con->scratchpad && !con->workspace; | 1654 | return con->scratchpad && !con->pending.workspace; |
1619 | } | 1655 | } |
1620 | 1656 | ||
1621 | bool container_is_scratchpad_hidden_or_child(struct sway_container *con) { | 1657 | bool container_is_scratchpad_hidden_or_child(struct sway_container *con) { |
1622 | con = container_toplevel_ancestor(con); | 1658 | con = container_toplevel_ancestor(con); |
1623 | return con->scratchpad && !con->workspace; | 1659 | return con->scratchpad && !con->pending.workspace; |
1624 | } | 1660 | } |
1625 | 1661 | ||
1626 | bool container_is_sticky(struct sway_container *con) { | 1662 | bool container_is_sticky(struct sway_container *con) { |
@@ -1648,39 +1684,39 @@ static bool is_parallel(enum sway_container_layout first, | |||
1648 | static bool container_is_squashable(struct sway_container *con, | 1684 | static bool container_is_squashable(struct sway_container *con, |
1649 | struct sway_container *child) { | 1685 | struct sway_container *child) { |
1650 | enum sway_container_layout gp_layout = container_parent_layout(con); | 1686 | enum sway_container_layout gp_layout = container_parent_layout(con); |
1651 | return (con->layout == L_HORIZ || con->layout == L_VERT) && | 1687 | return (con->pending.layout == L_HORIZ || con->pending.layout == L_VERT) && |
1652 | (child->layout == L_HORIZ || child->layout == L_VERT) && | 1688 | (child->pending.layout == L_HORIZ || child->pending.layout == L_VERT) && |
1653 | !is_parallel(con->layout, child->layout) && | 1689 | !is_parallel(con->pending.layout, child->pending.layout) && |
1654 | is_parallel(gp_layout, child->layout); | 1690 | is_parallel(gp_layout, child->pending.layout); |
1655 | } | 1691 | } |
1656 | 1692 | ||
1657 | static void container_squash_children(struct sway_container *con) { | 1693 | static void container_squash_children(struct sway_container *con) { |
1658 | for (int i = 0; i < con->children->length; i++) { | 1694 | for (int i = 0; i < con->pending.children->length; i++) { |
1659 | struct sway_container *child = con->children->items[i]; | 1695 | struct sway_container *child = con->pending.children->items[i]; |
1660 | i += container_squash(child); | 1696 | i += container_squash(child); |
1661 | } | 1697 | } |
1662 | } | 1698 | } |
1663 | 1699 | ||
1664 | int container_squash(struct sway_container *con) { | 1700 | int container_squash(struct sway_container *con) { |
1665 | if (!con->children) { | 1701 | if (!con->pending.children) { |
1666 | return 0; | 1702 | return 0; |
1667 | } | 1703 | } |
1668 | if (con->children->length != 1) { | 1704 | if (con->pending.children->length != 1) { |
1669 | container_squash_children(con); | 1705 | container_squash_children(con); |
1670 | return 0; | 1706 | return 0; |
1671 | } | 1707 | } |
1672 | struct sway_container *child = con->children->items[0]; | 1708 | struct sway_container *child = con->pending.children->items[0]; |
1673 | int idx = container_sibling_index(con); | 1709 | int idx = container_sibling_index(con); |
1674 | int change = 0; | 1710 | int change = 0; |
1675 | if (container_is_squashable(con, child)) { | 1711 | if (container_is_squashable(con, child)) { |
1676 | // con and child are a redundant H/V pair. Destroy them. | 1712 | // con and child are a redundant H/V pair. Destroy them. |
1677 | while (child->children->length) { | 1713 | while (child->pending.children->length) { |
1678 | struct sway_container *current = child->children->items[0]; | 1714 | struct sway_container *current = child->pending.children->items[0]; |
1679 | container_detach(current); | 1715 | container_detach(current); |
1680 | if (con->parent) { | 1716 | if (con->pending.parent) { |
1681 | container_insert_child(con->parent, current, idx); | 1717 | container_insert_child(con->pending.parent, current, idx); |
1682 | } else { | 1718 | } else { |
1683 | workspace_insert_tiling_direct(con->workspace, current, idx); | 1719 | workspace_insert_tiling_direct(con->pending.workspace, current, idx); |
1684 | } | 1720 | } |
1685 | change++; | 1721 | change++; |
1686 | } | 1722 | } |
diff --git a/sway/tree/node.c b/sway/tree/node.c index ffa7f2cc..bc7e2aa5 100644 --- a/sway/tree/node.c +++ b/sway/tree/node.c | |||
@@ -75,7 +75,7 @@ void node_get_box(struct sway_node *node, struct wlr_box *box) { | |||
75 | struct sway_output *node_get_output(struct sway_node *node) { | 75 | struct sway_output *node_get_output(struct sway_node *node) { |
76 | switch (node->type) { | 76 | switch (node->type) { |
77 | case N_CONTAINER: { | 77 | case N_CONTAINER: { |
78 | struct sway_workspace *ws = node->sway_container->workspace; | 78 | struct sway_workspace *ws = node->sway_container->pending.workspace; |
79 | return ws ? ws->output : NULL; | 79 | return ws ? ws->output : NULL; |
80 | } | 80 | } |
81 | case N_WORKSPACE: | 81 | case N_WORKSPACE: |
@@ -91,7 +91,7 @@ struct sway_output *node_get_output(struct sway_node *node) { | |||
91 | enum sway_container_layout node_get_layout(struct sway_node *node) { | 91 | enum sway_container_layout node_get_layout(struct sway_node *node) { |
92 | switch (node->type) { | 92 | switch (node->type) { |
93 | case N_CONTAINER: | 93 | case N_CONTAINER: |
94 | return node->sway_container->layout; | 94 | return node->sway_container->pending.layout; |
95 | case N_WORKSPACE: | 95 | case N_WORKSPACE: |
96 | return node->sway_workspace->layout; | 96 | return node->sway_workspace->layout; |
97 | case N_OUTPUT: | 97 | case N_OUTPUT: |
@@ -105,11 +105,11 @@ struct sway_node *node_get_parent(struct sway_node *node) { | |||
105 | switch (node->type) { | 105 | switch (node->type) { |
106 | case N_CONTAINER: { | 106 | case N_CONTAINER: { |
107 | struct sway_container *con = node->sway_container; | 107 | struct sway_container *con = node->sway_container; |
108 | if (con->parent) { | 108 | if (con->pending.parent) { |
109 | return &con->parent->node; | 109 | return &con->pending.parent->node; |
110 | } | 110 | } |
111 | if (con->workspace) { | 111 | if (con->pending.workspace) { |
112 | return &con->workspace->node; | 112 | return &con->pending.workspace->node; |
113 | } | 113 | } |
114 | } | 114 | } |
115 | return NULL; | 115 | return NULL; |
@@ -131,7 +131,7 @@ struct sway_node *node_get_parent(struct sway_node *node) { | |||
131 | list_t *node_get_children(struct sway_node *node) { | 131 | list_t *node_get_children(struct sway_node *node) { |
132 | switch (node->type) { | 132 | switch (node->type) { |
133 | case N_CONTAINER: | 133 | case N_CONTAINER: |
134 | return node->sway_container->children; | 134 | return node->sway_container->pending.children; |
135 | case N_WORKSPACE: | 135 | case N_WORKSPACE: |
136 | return node->sway_workspace->tiling; | 136 | return node->sway_workspace->tiling; |
137 | case N_OUTPUT: | 137 | case N_OUTPUT: |
@@ -143,7 +143,7 @@ list_t *node_get_children(struct sway_node *node) { | |||
143 | 143 | ||
144 | bool node_has_ancestor(struct sway_node *node, struct sway_node *ancestor) { | 144 | bool node_has_ancestor(struct sway_node *node, struct sway_node *ancestor) { |
145 | if (ancestor->type == N_ROOT && node->type == N_CONTAINER && | 145 | if (ancestor->type == N_ROOT && node->type == N_CONTAINER && |
146 | node->sway_container->fullscreen_mode == FULLSCREEN_GLOBAL) { | 146 | node->sway_container->pending.fullscreen_mode == FULLSCREEN_GLOBAL) { |
147 | return true; | 147 | return true; |
148 | } | 148 | } |
149 | struct sway_node *parent = node_get_parent(node); | 149 | struct sway_node *parent = node_get_parent(node); |
@@ -152,7 +152,7 @@ bool node_has_ancestor(struct sway_node *node, struct sway_node *ancestor) { | |||
152 | return true; | 152 | return true; |
153 | } | 153 | } |
154 | if (ancestor->type == N_ROOT && parent->type == N_CONTAINER && | 154 | if (ancestor->type == N_ROOT && parent->type == N_CONTAINER && |
155 | parent->sway_container->fullscreen_mode == FULLSCREEN_GLOBAL) { | 155 | parent->sway_container->pending.fullscreen_mode == FULLSCREEN_GLOBAL) { |
156 | return true; | 156 | return true; |
157 | } | 157 | } |
158 | parent = node_get_parent(parent); | 158 | parent = node_get_parent(parent); |
diff --git a/sway/tree/output.c b/sway/tree/output.c index a8ae30f7..c095dce0 100644 --- a/sway/tree/output.c +++ b/sway/tree/output.c | |||
@@ -70,13 +70,13 @@ static void restore_workspaces(struct sway_output *output) { | |||
70 | // floater re-centered | 70 | // floater re-centered |
71 | for (int i = 0; i < ws->floating->length; i++) { | 71 | for (int i = 0; i < ws->floating->length; i++) { |
72 | struct sway_container *floater = ws->floating->items[i]; | 72 | struct sway_container *floater = ws->floating->items[i]; |
73 | if (floater->width == 0 || floater->height == 0 || | 73 | if (floater->pending.width == 0 || floater->pending.height == 0 || |
74 | floater->width > output->width || | 74 | floater->pending.width > output->width || |
75 | floater->height > output->height || | 75 | floater->pending.height > output->height || |
76 | floater->x > output->lx + output->width || | 76 | floater->pending.x > output->lx + output->width || |
77 | floater->y > output->ly + output->height || | 77 | floater->pending.y > output->ly + output->height || |
78 | floater->x + floater->width < output->lx || | 78 | floater->pending.x + floater->pending.width < output->lx || |
79 | floater->y + floater->height < output->ly) { | 79 | floater->pending.y + floater->pending.height < output->ly) { |
80 | container_floating_resize_and_center(floater); | 80 | container_floating_resize_and_center(floater); |
81 | } | 81 | } |
82 | } | 82 | } |
diff --git a/sway/tree/root.c b/sway/tree/root.c index ebd185ec..dd4d8e33 100644 --- a/sway/tree/root.c +++ b/sway/tree/root.c | |||
@@ -59,11 +59,11 @@ void root_scratchpad_add_container(struct sway_container *con, struct sway_works | |||
59 | return; | 59 | return; |
60 | } | 60 | } |
61 | 61 | ||
62 | struct sway_container *parent = con->parent; | 62 | struct sway_container *parent = con->pending.parent; |
63 | struct sway_workspace *workspace = con->workspace; | 63 | struct sway_workspace *workspace = con->pending.workspace; |
64 | 64 | ||
65 | // Clear the fullscreen mode when sending to the scratchpad | 65 | // Clear the fullscreen mode when sending to the scratchpad |
66 | if (con->fullscreen_mode != FULLSCREEN_NONE) { | 66 | if (con->pending.fullscreen_mode != FULLSCREEN_NONE) { |
67 | container_fullscreen_disable(con); | 67 | container_fullscreen_disable(con); |
68 | } | 68 | } |
69 | 69 | ||
@@ -117,7 +117,7 @@ void root_scratchpad_show(struct sway_container *con) { | |||
117 | sway_log(SWAY_DEBUG, "No focused workspace to show scratchpad on"); | 117 | sway_log(SWAY_DEBUG, "No focused workspace to show scratchpad on"); |
118 | return; | 118 | return; |
119 | } | 119 | } |
120 | struct sway_workspace *old_ws = con->workspace; | 120 | struct sway_workspace *old_ws = con->pending.workspace; |
121 | 121 | ||
122 | // If the current con or any of its parents are in fullscreen mode, we | 122 | // If the current con or any of its parents are in fullscreen mode, we |
123 | // first need to disable it before showing the scratchpad con. | 123 | // first need to disable it before showing the scratchpad con. |
@@ -134,15 +134,15 @@ void root_scratchpad_show(struct sway_container *con) { | |||
134 | workspace_consider_destroy(old_ws); | 134 | workspace_consider_destroy(old_ws); |
135 | } else { | 135 | } else { |
136 | // Act on the ancestor of scratchpad hidden split containers | 136 | // Act on the ancestor of scratchpad hidden split containers |
137 | while (con->parent) { | 137 | while (con->pending.parent) { |
138 | con = con->parent; | 138 | con = con->pending.parent; |
139 | } | 139 | } |
140 | } | 140 | } |
141 | workspace_add_floating(new_ws, con); | 141 | workspace_add_floating(new_ws, con); |
142 | 142 | ||
143 | // Make sure the container's center point overlaps this workspace | 143 | // Make sure the container's center point overlaps this workspace |
144 | double center_lx = con->x + con->width / 2; | 144 | double center_lx = con->pending.x + con->pending.width / 2; |
145 | double center_ly = con->y + con->height / 2; | 145 | double center_ly = con->pending.y + con->pending.height / 2; |
146 | 146 | ||
147 | struct wlr_box workspace_box; | 147 | struct wlr_box workspace_box; |
148 | workspace_get_box(new_ws, &workspace_box); | 148 | workspace_get_box(new_ws, &workspace_box); |
@@ -155,7 +155,7 @@ void root_scratchpad_show(struct sway_container *con) { | |||
155 | } | 155 | } |
156 | 156 | ||
157 | static void disable_fullscreen(struct sway_container *con, void *data) { | 157 | static void disable_fullscreen(struct sway_container *con, void *data) { |
158 | if (con->fullscreen_mode != FULLSCREEN_NONE) { | 158 | if (con->pending.fullscreen_mode != FULLSCREEN_NONE) { |
159 | container_fullscreen_disable(con); | 159 | container_fullscreen_disable(con); |
160 | } | 160 | } |
161 | } | 161 | } |
@@ -163,9 +163,9 @@ static void disable_fullscreen(struct sway_container *con, void *data) { | |||
163 | void root_scratchpad_hide(struct sway_container *con) { | 163 | void root_scratchpad_hide(struct sway_container *con) { |
164 | struct sway_seat *seat = input_manager_current_seat(); | 164 | struct sway_seat *seat = input_manager_current_seat(); |
165 | struct sway_node *focus = seat_get_focus_inactive(seat, &root->node); | 165 | struct sway_node *focus = seat_get_focus_inactive(seat, &root->node); |
166 | struct sway_workspace *ws = con->workspace; | 166 | struct sway_workspace *ws = con->pending.workspace; |
167 | 167 | ||
168 | if (con->fullscreen_mode == FULLSCREEN_GLOBAL && !con->workspace) { | 168 | if (con->pending.fullscreen_mode == FULLSCREEN_GLOBAL && !con->pending.workspace) { |
169 | // If the container was made fullscreen global while in the scratchpad, | 169 | // If the container was made fullscreen global while in the scratchpad, |
170 | // it should be shown until fullscreen has been disabled | 170 | // it should be shown until fullscreen has been disabled |
171 | return; | 171 | return; |
@@ -270,7 +270,16 @@ found: | |||
270 | sway_log(SWAY_DEBUG, | 270 | sway_log(SWAY_DEBUG, |
271 | "Creating workspace %s for pid %d because it disappeared", | 271 | "Creating workspace %s for pid %d because it disappeared", |
272 | pw->workspace, pid); | 272 | pw->workspace, pid); |
273 | ws = workspace_create(pw->output, pw->workspace); | 273 | |
274 | struct sway_output *output = pw->output; | ||
275 | if (pw->output && !pw->output->enabled) { | ||
276 | sway_log(SWAY_DEBUG, | ||
277 | "Workspace output %s is disabled, trying another one", | ||
278 | pw->output->wlr_output->name); | ||
279 | output = NULL; | ||
280 | } | ||
281 | |||
282 | ws = workspace_create(output, pw->workspace); | ||
274 | } | 283 | } |
275 | 284 | ||
276 | pid_workspace_destroy(pw); | 285 | pid_workspace_destroy(pw); |
diff --git a/sway/tree/view.c b/sway/tree/view.c index 7afcdf31..b2f70d70 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -56,6 +56,7 @@ void view_destroy(struct sway_view *view) { | |||
56 | "(might have a pending transaction?)")) { | 56 | "(might have a pending transaction?)")) { |
57 | return; | 57 | return; |
58 | } | 58 | } |
59 | wl_list_remove(&view->events.unmap.listener_list); | ||
59 | if (!wl_list_empty(&view->saved_buffers)) { | 60 | if (!wl_list_empty(&view->saved_buffers)) { |
60 | view_remove_saved_buffer(view); | 61 | view_remove_saved_buffer(view); |
61 | } | 62 | } |
@@ -206,7 +207,7 @@ bool view_ancestor_is_only_visible(struct sway_view *view) { | |||
206 | } else { | 207 | } else { |
207 | only_visible = true; | 208 | only_visible = true; |
208 | } | 209 | } |
209 | con = con->parent; | 210 | con = con->pending.parent; |
210 | } | 211 | } |
211 | return only_visible; | 212 | return only_visible; |
212 | } | 213 | } |
@@ -222,72 +223,73 @@ static bool view_is_only_visible(struct sway_view *view) { | |||
222 | } | 223 | } |
223 | } | 224 | } |
224 | 225 | ||
225 | con = con->parent; | 226 | con = con->pending.parent; |
226 | } | 227 | } |
227 | 228 | ||
228 | return true; | 229 | return true; |
229 | } | 230 | } |
230 | 231 | ||
231 | static bool gaps_to_edge(struct sway_view *view) { | 232 | static bool gaps_to_edge(struct sway_view *view) { |
232 | struct side_gaps gaps = view->container->workspace->current_gaps; | 233 | struct side_gaps gaps = view->container->pending.workspace->current_gaps; |
233 | return gaps.top > 0 || gaps.right > 0 || gaps.bottom > 0 || gaps.left > 0; | 234 | return gaps.top > 0 || gaps.right > 0 || gaps.bottom > 0 || gaps.left > 0; |
234 | } | 235 | } |
235 | 236 | ||
236 | void view_autoconfigure(struct sway_view *view) { | 237 | void view_autoconfigure(struct sway_view *view) { |
237 | struct sway_container *con = view->container; | 238 | struct sway_container *con = view->container; |
238 | struct sway_workspace *ws = con->workspace; | 239 | struct sway_workspace *ws = con->pending.workspace; |
239 | 240 | ||
240 | if (container_is_scratchpad_hidden(con) && | 241 | if (container_is_scratchpad_hidden(con) && |
241 | con->fullscreen_mode != FULLSCREEN_GLOBAL) { | 242 | con->pending.fullscreen_mode != FULLSCREEN_GLOBAL) { |
242 | return; | 243 | return; |
243 | } | 244 | } |
244 | struct sway_output *output = ws ? ws->output : NULL; | 245 | struct sway_output *output = ws ? ws->output : NULL; |
245 | 246 | ||
246 | if (con->fullscreen_mode == FULLSCREEN_WORKSPACE) { | 247 | if (con->pending.fullscreen_mode == FULLSCREEN_WORKSPACE) { |
247 | con->content_x = output->lx; | 248 | con->pending.content_x = output->lx; |
248 | con->content_y = output->ly; | 249 | con->pending.content_y = output->ly; |
249 | con->content_width = output->width; | 250 | con->pending.content_width = output->width; |
250 | con->content_height = output->height; | 251 | con->pending.content_height = output->height; |
251 | return; | 252 | return; |
252 | } else if (con->fullscreen_mode == FULLSCREEN_GLOBAL) { | 253 | } else if (con->pending.fullscreen_mode == FULLSCREEN_GLOBAL) { |
253 | con->content_x = root->x; | 254 | con->pending.content_x = root->x; |
254 | con->content_y = root->y; | 255 | con->pending.content_y = root->y; |
255 | con->content_width = root->width; | 256 | con->pending.content_width = root->width; |
256 | con->content_height = root->height; | 257 | con->pending.content_height = root->height; |
257 | return; | 258 | return; |
258 | } | 259 | } |
259 | 260 | ||
260 | con->border_top = con->border_bottom = true; | 261 | con->pending.border_top = con->pending.border_bottom = true; |
261 | con->border_left = con->border_right = true; | 262 | con->pending.border_left = con->pending.border_right = true; |
262 | double y_offset = 0; | 263 | double y_offset = 0; |
263 | 264 | ||
264 | if (!container_is_floating(con) && ws) { | 265 | if (!container_is_floating_or_child(con) && ws) { |
265 | if (config->hide_edge_borders == E_BOTH | 266 | if (config->hide_edge_borders == E_BOTH |
266 | || config->hide_edge_borders == E_VERTICAL) { | 267 | || config->hide_edge_borders == E_VERTICAL) { |
267 | con->border_left = con->x != ws->x; | 268 | con->pending.border_left = con->pending.x != ws->x; |
268 | int right_x = con->x + con->width; | 269 | int right_x = con->pending.x + con->pending.width; |
269 | con->border_right = right_x != ws->x + ws->width; | 270 | con->pending.border_right = right_x != ws->x + ws->width; |
270 | } | 271 | } |
271 | 272 | ||
272 | if (config->hide_edge_borders == E_BOTH | 273 | if (config->hide_edge_borders == E_BOTH |
273 | || config->hide_edge_borders == E_HORIZONTAL) { | 274 | || config->hide_edge_borders == E_HORIZONTAL) { |
274 | con->border_top = con->y != ws->y; | 275 | con->pending.border_top = con->pending.y != ws->y; |
275 | int bottom_y = con->y + con->height; | 276 | int bottom_y = con->pending.y + con->pending.height; |
276 | con->border_bottom = bottom_y != ws->y + ws->height; | 277 | con->pending.border_bottom = bottom_y != ws->y + ws->height; |
277 | } | 278 | } |
278 | 279 | ||
279 | bool smart = config->hide_edge_borders_smart == ESMART_ON || | 280 | bool smart = config->hide_edge_borders_smart == ESMART_ON || |
280 | (config->hide_edge_borders_smart == ESMART_NO_GAPS && | 281 | (config->hide_edge_borders_smart == ESMART_NO_GAPS && |
281 | !gaps_to_edge(view)); | 282 | !gaps_to_edge(view)); |
282 | if (smart) { | 283 | if (smart) { |
283 | bool show_border = container_is_floating_or_child(con) || | 284 | bool show_border = !view_is_only_visible(view); |
284 | !view_is_only_visible(view); | 285 | con->pending.border_left &= show_border; |
285 | con->border_left &= show_border; | 286 | con->pending.border_right &= show_border; |
286 | con->border_right &= show_border; | 287 | con->pending.border_top &= show_border; |
287 | con->border_top &= show_border; | 288 | con->pending.border_bottom &= show_border; |
288 | con->border_bottom &= show_border; | ||
289 | } | 289 | } |
290 | } | ||
290 | 291 | ||
292 | if (!container_is_floating(con)) { | ||
291 | // In a tabbed or stacked container, the container's y is the top of the | 293 | // In a tabbed or stacked container, the container's y is the top of the |
292 | // title area. We have to offset the surface y by the height of the title, | 294 | // title area. We have to offset the surface y by the height of the title, |
293 | // bar, and disable any top border because we'll always have the title bar. | 295 | // bar, and disable any top border because we'll always have the title bar. |
@@ -298,56 +300,56 @@ void view_autoconfigure(struct sway_view *view) { | |||
298 | enum sway_container_layout layout = container_parent_layout(con); | 300 | enum sway_container_layout layout = container_parent_layout(con); |
299 | if (layout == L_TABBED) { | 301 | if (layout == L_TABBED) { |
300 | y_offset = container_titlebar_height(); | 302 | y_offset = container_titlebar_height(); |
301 | con->border_top = false; | 303 | con->pending.border_top = false; |
302 | } else if (layout == L_STACKED) { | 304 | } else if (layout == L_STACKED) { |
303 | y_offset = container_titlebar_height() * siblings->length; | 305 | y_offset = container_titlebar_height() * siblings->length; |
304 | con->border_top = false; | 306 | con->pending.border_top = false; |
305 | } | 307 | } |
306 | } | 308 | } |
307 | } | 309 | } |
308 | 310 | ||
309 | double x, y, width, height; | 311 | double x, y, width, height; |
310 | switch (con->border) { | 312 | switch (con->pending.border) { |
311 | default: | 313 | default: |
312 | case B_CSD: | 314 | case B_CSD: |
313 | case B_NONE: | 315 | case B_NONE: |
314 | x = con->x; | 316 | x = con->pending.x; |
315 | y = con->y + y_offset; | 317 | y = con->pending.y + y_offset; |
316 | width = con->width; | 318 | width = con->pending.width; |
317 | height = con->height - y_offset; | 319 | height = con->pending.height - y_offset; |
318 | break; | 320 | break; |
319 | case B_PIXEL: | 321 | case B_PIXEL: |
320 | x = con->x + con->border_thickness * con->border_left; | 322 | x = con->pending.x + con->pending.border_thickness * con->pending.border_left; |
321 | y = con->y + con->border_thickness * con->border_top + y_offset; | 323 | y = con->pending.y + con->pending.border_thickness * con->pending.border_top + y_offset; |
322 | width = con->width | 324 | width = con->pending.width |
323 | - con->border_thickness * con->border_left | 325 | - con->pending.border_thickness * con->pending.border_left |
324 | - con->border_thickness * con->border_right; | 326 | - con->pending.border_thickness * con->pending.border_right; |
325 | height = con->height - y_offset | 327 | height = con->pending.height - y_offset |
326 | - con->border_thickness * con->border_top | 328 | - con->pending.border_thickness * con->pending.border_top |
327 | - con->border_thickness * con->border_bottom; | 329 | - con->pending.border_thickness * con->pending.border_bottom; |
328 | break; | 330 | break; |
329 | case B_NORMAL: | 331 | case B_NORMAL: |
330 | // Height is: 1px border + 3px pad + title height + 3px pad + 1px border | 332 | // Height is: 1px border + 3px pad + title height + 3px pad + 1px border |
331 | x = con->x + con->border_thickness * con->border_left; | 333 | x = con->pending.x + con->pending.border_thickness * con->pending.border_left; |
332 | width = con->width | 334 | width = con->pending.width |
333 | - con->border_thickness * con->border_left | 335 | - con->pending.border_thickness * con->pending.border_left |
334 | - con->border_thickness * con->border_right; | 336 | - con->pending.border_thickness * con->pending.border_right; |
335 | if (y_offset) { | 337 | if (y_offset) { |
336 | y = con->y + y_offset; | 338 | y = con->pending.y + y_offset; |
337 | height = con->height - y_offset | 339 | height = con->pending.height - y_offset |
338 | - con->border_thickness * con->border_bottom; | 340 | - con->pending.border_thickness * con->pending.border_bottom; |
339 | } else { | 341 | } else { |
340 | y = con->y + container_titlebar_height(); | 342 | y = con->pending.y + container_titlebar_height(); |
341 | height = con->height - container_titlebar_height() | 343 | height = con->pending.height - container_titlebar_height() |
342 | - con->border_thickness * con->border_bottom; | 344 | - con->pending.border_thickness * con->pending.border_bottom; |
343 | } | 345 | } |
344 | break; | 346 | break; |
345 | } | 347 | } |
346 | 348 | ||
347 | con->content_x = x; | 349 | con->pending.content_x = x; |
348 | con->content_y = y; | 350 | con->pending.content_y = y; |
349 | con->content_width = width; | 351 | con->pending.content_width = width; |
350 | con->content_height = height; | 352 | con->pending.content_height = height; |
351 | } | 353 | } |
352 | 354 | ||
353 | void view_set_activated(struct sway_view *view, bool activated) { | 355 | void view_set_activated(struct sway_view *view, bool activated) { |
@@ -361,7 +363,7 @@ void view_set_activated(struct sway_view *view, bool activated) { | |||
361 | } | 363 | } |
362 | 364 | ||
363 | void view_request_activate(struct sway_view *view) { | 365 | void view_request_activate(struct sway_view *view) { |
364 | struct sway_workspace *ws = view->container->workspace; | 366 | struct sway_workspace *ws = view->container->pending.workspace; |
365 | if (!ws) { // hidden scratchpad container | 367 | if (!ws) { // hidden scratchpad container |
366 | return; | 368 | return; |
367 | } | 369 | } |
@@ -401,13 +403,13 @@ void view_set_csd_from_server(struct sway_view *view, bool enabled) { | |||
401 | void view_update_csd_from_client(struct sway_view *view, bool enabled) { | 403 | void view_update_csd_from_client(struct sway_view *view, bool enabled) { |
402 | sway_log(SWAY_DEBUG, "View %p updated CSD to %i", view, enabled); | 404 | sway_log(SWAY_DEBUG, "View %p updated CSD to %i", view, enabled); |
403 | struct sway_container *con = view->container; | 405 | struct sway_container *con = view->container; |
404 | if (enabled && con && con->border != B_CSD) { | 406 | if (enabled && con && con->pending.border != B_CSD) { |
405 | con->saved_border = con->border; | 407 | con->saved_border = con->pending.border; |
406 | if (container_is_floating(con)) { | 408 | if (container_is_floating(con)) { |
407 | con->border = B_CSD; | 409 | con->pending.border = B_CSD; |
408 | } | 410 | } |
409 | } else if (!enabled && con && con->border == B_CSD) { | 411 | } else if (!enabled && con && con->pending.border == B_CSD) { |
410 | con->border = con->saved_border; | 412 | con->pending.border = con->saved_border; |
411 | } | 413 | } |
412 | view->using_csd = enabled; | 414 | view->using_csd = enabled; |
413 | } | 415 | } |
@@ -465,6 +467,9 @@ static void view_subsurface_create(struct sway_view *view, | |||
465 | static void view_init_subsurfaces(struct sway_view *view, | 467 | static void view_init_subsurfaces(struct sway_view *view, |
466 | struct wlr_surface *surface); | 468 | struct wlr_surface *surface); |
467 | 469 | ||
470 | static void view_child_init_subsurfaces(struct sway_view_child *view_child, | ||
471 | struct wlr_surface *surface); | ||
472 | |||
468 | static void view_handle_surface_new_subsurface(struct wl_listener *listener, | 473 | static void view_handle_surface_new_subsurface(struct wl_listener *listener, |
469 | void *data) { | 474 | void *data) { |
470 | struct sway_view *view = | 475 | struct sway_view *view = |
@@ -577,7 +582,7 @@ static struct sway_workspace *select_workspace(struct sway_view *view) { | |||
577 | if (node && node->type == N_WORKSPACE) { | 582 | if (node && node->type == N_WORKSPACE) { |
578 | return node->sway_workspace; | 583 | return node->sway_workspace; |
579 | } else if (node && node->type == N_CONTAINER) { | 584 | } else if (node && node->type == N_CONTAINER) { |
580 | return node->sway_container->workspace; | 585 | return node->sway_container->pending.workspace; |
581 | } | 586 | } |
582 | 587 | ||
583 | // When there's no outputs connected, the above should match a workspace on | 588 | // When there's no outputs connected, the above should match a workspace on |
@@ -590,12 +595,17 @@ static bool should_focus(struct sway_view *view) { | |||
590 | struct sway_seat *seat = input_manager_current_seat(); | 595 | struct sway_seat *seat = input_manager_current_seat(); |
591 | struct sway_container *prev_con = seat_get_focused_container(seat); | 596 | struct sway_container *prev_con = seat_get_focused_container(seat); |
592 | struct sway_workspace *prev_ws = seat_get_focused_workspace(seat); | 597 | struct sway_workspace *prev_ws = seat_get_focused_workspace(seat); |
593 | struct sway_workspace *map_ws = view->container->workspace; | 598 | struct sway_workspace *map_ws = view->container->pending.workspace; |
594 | 599 | ||
595 | if (view->container->fullscreen_mode == FULLSCREEN_GLOBAL) { | 600 | if (view->container->pending.fullscreen_mode == FULLSCREEN_GLOBAL) { |
596 | return true; | 601 | return true; |
597 | } | 602 | } |
598 | 603 | ||
604 | // View opened "under" fullscreen view should not be given focus. | ||
605 | if (root->fullscreen_global || !map_ws || map_ws->fullscreen) { | ||
606 | return false; | ||
607 | } | ||
608 | |||
599 | // Views can only take focus if they are mapped into the active workspace | 609 | // Views can only take focus if they are mapped into the active workspace |
600 | if (prev_ws != map_ws) { | 610 | if (prev_ws != map_ws) { |
601 | return false; | 611 | return false; |
@@ -603,9 +613,9 @@ static bool should_focus(struct sway_view *view) { | |||
603 | 613 | ||
604 | // If the view is the only one in the focused workspace, it'll get focus | 614 | // If the view is the only one in the focused workspace, it'll get focus |
605 | // regardless of any no_focus criteria. | 615 | // regardless of any no_focus criteria. |
606 | if (!view->container->parent && !prev_con) { | 616 | if (!view->container->pending.parent && !prev_con) { |
607 | size_t num_children = view->container->workspace->tiling->length + | 617 | size_t num_children = view->container->pending.workspace->tiling->length + |
608 | view->container->workspace->floating->length; | 618 | view->container->pending.workspace->floating->length; |
609 | if (num_children == 1) { | 619 | if (num_children == 1) { |
610 | return true; | 620 | return true; |
611 | } | 621 | } |
@@ -635,6 +645,7 @@ static void handle_foreign_activate_request( | |||
635 | break; | 645 | break; |
636 | } | 646 | } |
637 | } | 647 | } |
648 | transaction_commit_dirty(); | ||
638 | } | 649 | } |
639 | 650 | ||
640 | static void handle_foreign_fullscreen_request( | 651 | static void handle_foreign_fullscreen_request( |
@@ -645,9 +656,21 @@ static void handle_foreign_fullscreen_request( | |||
645 | 656 | ||
646 | // Match fullscreen command behavior for scratchpad hidden views | 657 | // Match fullscreen command behavior for scratchpad hidden views |
647 | struct sway_container *container = view->container; | 658 | struct sway_container *container = view->container; |
648 | if (!container->workspace) { | 659 | if (!container->pending.workspace) { |
649 | while (container->parent) { | 660 | while (container->pending.parent) { |
650 | container = container->parent; | 661 | container = container->pending.parent; |
662 | } | ||
663 | } | ||
664 | |||
665 | if (event->fullscreen && event->output && event->output->data) { | ||
666 | struct sway_output *output = event->output->data; | ||
667 | struct sway_workspace *ws = output_get_active_workspace(output); | ||
668 | if (ws && !container_is_scratchpad_hidden(view->container)) { | ||
669 | if (container_is_floating(view->container)) { | ||
670 | workspace_add_floating(ws, view->container); | ||
671 | } else { | ||
672 | workspace_add_tiling(ws, view->container); | ||
673 | } | ||
651 | } | 674 | } |
652 | } | 675 | } |
653 | 676 | ||
@@ -656,12 +679,13 @@ static void handle_foreign_fullscreen_request( | |||
656 | if (event->fullscreen) { | 679 | if (event->fullscreen) { |
657 | arrange_root(); | 680 | arrange_root(); |
658 | } else { | 681 | } else { |
659 | if (container->parent) { | 682 | if (container->pending.parent) { |
660 | arrange_container(container->parent); | 683 | arrange_container(container->pending.parent); |
661 | } else if (container->workspace) { | 684 | } else if (container->pending.workspace) { |
662 | arrange_workspace(container->workspace); | 685 | arrange_workspace(container->pending.workspace); |
663 | } | 686 | } |
664 | } | 687 | } |
688 | transaction_commit_dirty(); | ||
665 | } | 689 | } |
666 | 690 | ||
667 | static void handle_foreign_close_request( | 691 | static void handle_foreign_close_request( |
@@ -742,7 +766,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, | |||
742 | 766 | ||
743 | view_init_subsurfaces(view, wlr_surface); | 767 | view_init_subsurfaces(view, wlr_surface); |
744 | wl_signal_add(&wlr_surface->events.new_subsurface, | 768 | wl_signal_add(&wlr_surface->events.new_subsurface, |
745 | &view->surface_new_subsurface); | 769 | &view->surface_new_subsurface); |
746 | view->surface_new_subsurface.notify = view_handle_surface_new_subsurface; | 770 | view->surface_new_subsurface.notify = view_handle_surface_new_subsurface; |
747 | 771 | ||
748 | if (decoration) { | 772 | if (decoration) { |
@@ -750,20 +774,20 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, | |||
750 | } | 774 | } |
751 | 775 | ||
752 | if (view->impl->wants_floating && view->impl->wants_floating(view)) { | 776 | if (view->impl->wants_floating && view->impl->wants_floating(view)) { |
753 | view->container->border = config->floating_border; | 777 | view->container->pending.border = config->floating_border; |
754 | view->container->border_thickness = config->floating_border_thickness; | 778 | view->container->pending.border_thickness = config->floating_border_thickness; |
755 | container_set_floating(view->container, true); | 779 | container_set_floating(view->container, true); |
756 | } else { | 780 | } else { |
757 | view->container->border = config->border; | 781 | view->container->pending.border = config->border; |
758 | view->container->border_thickness = config->border_thickness; | 782 | view->container->pending.border_thickness = config->border_thickness; |
759 | view_set_tiled(view, true); | 783 | view_set_tiled(view, true); |
760 | } | 784 | } |
761 | 785 | ||
762 | if (config->popup_during_fullscreen == POPUP_LEAVE && | 786 | if (config->popup_during_fullscreen == POPUP_LEAVE && |
763 | container->workspace && | 787 | container->pending.workspace && |
764 | container->workspace->fullscreen && | 788 | container->pending.workspace->fullscreen && |
765 | container->workspace->fullscreen->view) { | 789 | container->pending.workspace->fullscreen->view) { |
766 | struct sway_container *fs = container->workspace->fullscreen; | 790 | struct sway_container *fs = container->pending.workspace->fullscreen; |
767 | if (view_is_transient_for(view, fs->view)) { | 791 | if (view_is_transient_for(view, fs->view)) { |
768 | container_set_fullscreen(fs, false); | 792 | container_set_fullscreen(fs, false); |
769 | } | 793 | } |
@@ -774,12 +798,12 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, | |||
774 | 798 | ||
775 | if (fullscreen) { | 799 | if (fullscreen) { |
776 | container_set_fullscreen(view->container, true); | 800 | container_set_fullscreen(view->container, true); |
777 | arrange_workspace(view->container->workspace); | 801 | arrange_workspace(view->container->pending.workspace); |
778 | } else { | 802 | } else { |
779 | if (container->parent) { | 803 | if (container->pending.parent) { |
780 | arrange_container(container->parent); | 804 | arrange_container(container->pending.parent); |
781 | } else if (container->workspace) { | 805 | } else if (container->pending.workspace) { |
782 | arrange_workspace(container->workspace); | 806 | arrange_workspace(container->pending.workspace); |
783 | } | 807 | } |
784 | } | 808 | } |
785 | 809 | ||
@@ -790,9 +814,9 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, | |||
790 | #if HAVE_XWAYLAND | 814 | #if HAVE_XWAYLAND |
791 | if (wlr_surface_is_xwayland_surface(wlr_surface)) { | 815 | if (wlr_surface_is_xwayland_surface(wlr_surface)) { |
792 | struct wlr_xwayland_surface *xsurface = | 816 | struct wlr_xwayland_surface *xsurface = |
793 | wlr_xwayland_surface_from_wlr_surface(wlr_surface); | 817 | wlr_xwayland_surface_from_wlr_surface(wlr_surface); |
794 | set_focus = (wlr_xwayland_icccm_input_model(xsurface) != | 818 | set_focus &= wlr_xwayland_icccm_input_model(xsurface) != |
795 | WLR_ICCCM_INPUT_MODEL_NONE) && set_focus; | 819 | WLR_ICCCM_INPUT_MODEL_NONE; |
796 | } | 820 | } |
797 | #endif | 821 | #endif |
798 | 822 | ||
@@ -803,11 +827,9 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface, | |||
803 | const char *app_id; | 827 | const char *app_id; |
804 | const char *class; | 828 | const char *class; |
805 | if ((app_id = view_get_app_id(view)) != NULL) { | 829 | if ((app_id = view_get_app_id(view)) != NULL) { |
806 | wlr_foreign_toplevel_handle_v1_set_app_id( | 830 | wlr_foreign_toplevel_handle_v1_set_app_id(view->foreign_toplevel, app_id); |
807 | view->foreign_toplevel, app_id); | ||
808 | } else if ((class = view_get_class(view)) != NULL) { | 831 | } else if ((class = view_get_class(view)) != NULL) { |
809 | wlr_foreign_toplevel_handle_v1_set_app_id( | 832 | wlr_foreign_toplevel_handle_v1_set_app_id(view->foreign_toplevel, class); |
810 | view->foreign_toplevel, class); | ||
811 | } | 833 | } |
812 | } | 834 | } |
813 | 835 | ||
@@ -826,8 +848,8 @@ void view_unmap(struct sway_view *view) { | |||
826 | view->foreign_toplevel = NULL; | 848 | view->foreign_toplevel = NULL; |
827 | } | 849 | } |
828 | 850 | ||
829 | struct sway_container *parent = view->container->parent; | 851 | struct sway_container *parent = view->container->pending.parent; |
830 | struct sway_workspace *ws = view->container->workspace; | 852 | struct sway_workspace *ws = view->container->pending.workspace; |
831 | container_begin_destroy(view->container); | 853 | container_begin_destroy(view->container); |
832 | if (parent) { | 854 | if (parent) { |
833 | container_reap_empty(parent); | 855 | container_reap_empty(parent); |
@@ -860,47 +882,38 @@ void view_unmap(struct sway_view *view) { | |||
860 | view->surface = NULL; | 882 | view->surface = NULL; |
861 | } | 883 | } |
862 | 884 | ||
863 | void view_update_size(struct sway_view *view, int width, int height) { | 885 | void view_update_size(struct sway_view *view) { |
864 | struct sway_container *con = view->container; | 886 | struct sway_container *con = view->container; |
887 | con->pending.content_width = view->geometry.width; | ||
888 | con->pending.content_height = view->geometry.height; | ||
889 | container_set_geometry_from_content(con); | ||
890 | } | ||
865 | 891 | ||
866 | if (container_is_floating(con)) { | 892 | void view_center_surface(struct sway_view *view) { |
867 | con->content_width = width; | 893 | struct sway_container *con = view->container; |
868 | con->content_height = height; | 894 | // We always center the current coordinates rather than the next, as the |
869 | container_set_geometry_from_content(con); | 895 | // geometry immediately affects the currently active rendering. |
870 | } else { | 896 | con->surface_x = fmax(con->current.content_x, con->current.content_x + |
871 | con->surface_x = con->content_x + (con->content_width - width) / 2; | 897 | (con->current.content_width - view->geometry.width) / 2); |
872 | con->surface_y = con->content_y + (con->content_height - height) / 2; | 898 | con->surface_y = fmax(con->current.content_y, con->current.content_y + |
873 | con->surface_x = fmax(con->surface_x, con->content_x); | 899 | (con->current.content_height - view->geometry.height) / 2); |
874 | con->surface_y = fmax(con->surface_y, con->content_y); | ||
875 | } | ||
876 | } | 900 | } |
877 | 901 | ||
878 | static const struct sway_view_child_impl subsurface_impl; | 902 | static const struct sway_view_child_impl subsurface_impl; |
879 | 903 | ||
880 | static void subsurface_get_root_coords(struct sway_view_child *child, | 904 | static void subsurface_get_view_coords(struct sway_view_child *child, |
881 | int *root_sx, int *root_sy) { | 905 | int *sx, int *sy) { |
882 | struct wlr_surface *surface = child->surface; | 906 | struct wlr_surface *surface = child->surface; |
883 | *root_sx = -child->view->geometry.x; | ||
884 | *root_sy = -child->view->geometry.y; | ||
885 | |||
886 | if (child->parent && child->parent->impl && | 907 | if (child->parent && child->parent->impl && |
887 | child->parent->impl->get_root_coords) { | 908 | child->parent->impl->get_view_coords) { |
888 | int sx, sy; | 909 | child->parent->impl->get_view_coords(child->parent, sx, sy); |
889 | child->parent->impl->get_root_coords(child->parent, &sx, &sy); | ||
890 | *root_sx += sx; | ||
891 | *root_sy += sy; | ||
892 | } else { | 910 | } else { |
893 | while (surface && wlr_surface_is_subsurface(surface)) { | 911 | *sx = *sy = 0; |
894 | struct wlr_subsurface *subsurface = | ||
895 | wlr_subsurface_from_wlr_surface(surface); | ||
896 | if (subsurface == NULL) { | ||
897 | break; | ||
898 | } | ||
899 | *root_sx += subsurface->current.x; | ||
900 | *root_sy += subsurface->current.y; | ||
901 | surface = subsurface->parent; | ||
902 | } | ||
903 | } | 912 | } |
913 | struct wlr_subsurface *subsurface = | ||
914 | wlr_subsurface_from_wlr_surface(surface); | ||
915 | *sx += subsurface->current.x; | ||
916 | *sy += subsurface->current.y; | ||
904 | } | 917 | } |
905 | 918 | ||
906 | static void subsurface_destroy(struct sway_view_child *child) { | 919 | static void subsurface_destroy(struct sway_view_child *child) { |
@@ -914,7 +927,7 @@ static void subsurface_destroy(struct sway_view_child *child) { | |||
914 | } | 927 | } |
915 | 928 | ||
916 | static const struct sway_view_child_impl subsurface_impl = { | 929 | static const struct sway_view_child_impl subsurface_impl = { |
917 | .get_root_coords = subsurface_get_root_coords, | 930 | .get_view_coords = subsurface_get_view_coords, |
918 | .destroy = subsurface_destroy, | 931 | .destroy = subsurface_destroy, |
919 | }; | 932 | }; |
920 | 933 | ||
@@ -968,15 +981,27 @@ static void view_child_subsurface_create(struct sway_view_child *child, | |||
968 | view_child_damage(&subsurface->child, true); | 981 | view_child_damage(&subsurface->child, true); |
969 | } | 982 | } |
970 | 983 | ||
984 | static bool view_child_is_mapped(struct sway_view_child *child) { | ||
985 | while (child) { | ||
986 | if (!child->mapped) { | ||
987 | return false; | ||
988 | } | ||
989 | child = child->parent; | ||
990 | } | ||
991 | return true; | ||
992 | } | ||
993 | |||
971 | static void view_child_damage(struct sway_view_child *child, bool whole) { | 994 | static void view_child_damage(struct sway_view_child *child, bool whole) { |
972 | if (!child || !child->mapped || !child->view || !child->view->container) { | 995 | if (!child || !view_child_is_mapped(child) || !child->view || !child->view->container) { |
973 | return; | 996 | return; |
974 | } | 997 | } |
975 | int sx, sy; | 998 | int sx, sy; |
976 | child->impl->get_root_coords(child, &sx, &sy); | 999 | child->impl->get_view_coords(child, &sx, &sy); |
977 | desktop_damage_surface(child->surface, | 1000 | desktop_damage_surface(child->surface, |
978 | child->view->container->content_x + sx, | 1001 | child->view->container->pending.content_x - |
979 | child->view->container->content_y + sy, whole); | 1002 | child->view->geometry.x + sx, |
1003 | child->view->container->pending.content_y - | ||
1004 | child->view->geometry.y + sy, whole); | ||
980 | } | 1005 | } |
981 | 1006 | ||
982 | static void view_child_handle_surface_commit(struct wl_listener *listener, | 1007 | static void view_child_handle_surface_commit(struct wl_listener *listener, |
@@ -1004,11 +1029,29 @@ static void view_child_handle_surface_destroy(struct wl_listener *listener, | |||
1004 | static void view_init_subsurfaces(struct sway_view *view, | 1029 | static void view_init_subsurfaces(struct sway_view *view, |
1005 | struct wlr_surface *surface) { | 1030 | struct wlr_surface *surface) { |
1006 | struct wlr_subsurface *subsurface; | 1031 | struct wlr_subsurface *subsurface; |
1007 | wl_list_for_each(subsurface, &surface->subsurfaces, parent_link) { | 1032 | wl_list_for_each(subsurface, &surface->current.subsurfaces_below, |
1033 | current.link) { | ||
1034 | view_subsurface_create(view, subsurface); | ||
1035 | } | ||
1036 | wl_list_for_each(subsurface, &surface->current.subsurfaces_above, | ||
1037 | current.link) { | ||
1008 | view_subsurface_create(view, subsurface); | 1038 | view_subsurface_create(view, subsurface); |
1009 | } | 1039 | } |
1010 | } | 1040 | } |
1011 | 1041 | ||
1042 | static void view_child_init_subsurfaces(struct sway_view_child *view_child, | ||
1043 | struct wlr_surface *surface) { | ||
1044 | struct wlr_subsurface *subsurface; | ||
1045 | wl_list_for_each(subsurface, &surface->current.subsurfaces_below, | ||
1046 | current.link) { | ||
1047 | view_child_subsurface_create(view_child, subsurface); | ||
1048 | } | ||
1049 | wl_list_for_each(subsurface, &surface->current.subsurfaces_above, | ||
1050 | current.link) { | ||
1051 | view_child_subsurface_create(view_child, subsurface); | ||
1052 | } | ||
1053 | } | ||
1054 | |||
1012 | static void view_child_handle_surface_map(struct wl_listener *listener, | 1055 | static void view_child_handle_surface_map(struct wl_listener *listener, |
1013 | void *data) { | 1056 | void *data) { |
1014 | struct sway_view_child *child = | 1057 | struct sway_view_child *child = |
@@ -1059,16 +1102,16 @@ void view_child_init(struct sway_view_child *child, | |||
1059 | wl_signal_add(&view->events.unmap, &child->view_unmap); | 1102 | wl_signal_add(&view->events.unmap, &child->view_unmap); |
1060 | child->view_unmap.notify = view_child_handle_view_unmap; | 1103 | child->view_unmap.notify = view_child_handle_view_unmap; |
1061 | 1104 | ||
1062 | struct sway_workspace *workspace = child->view->container->workspace; | 1105 | struct sway_workspace *workspace = child->view->container->pending.workspace; |
1063 | if (workspace) { | 1106 | if (workspace) { |
1064 | wlr_surface_send_enter(child->surface, workspace->output->wlr_output); | 1107 | wlr_surface_send_enter(child->surface, workspace->output->wlr_output); |
1065 | } | 1108 | } |
1066 | 1109 | ||
1067 | view_init_subsurfaces(child->view, surface); | 1110 | view_child_init_subsurfaces(child, surface); |
1068 | } | 1111 | } |
1069 | 1112 | ||
1070 | void view_child_destroy(struct sway_view_child *child) { | 1113 | void view_child_destroy(struct sway_view_child *child) { |
1071 | if (child->mapped && child->view->container != NULL) { | 1114 | if (view_child_is_mapped(child) && child->view->container != NULL) { |
1072 | view_child_damage(child, true); | 1115 | view_child_damage(child, true); |
1073 | } | 1116 | } |
1074 | 1117 | ||
@@ -1081,6 +1124,9 @@ void view_child_destroy(struct sway_view_child *child) { | |||
1081 | wl_list_for_each_safe(subchild, tmpchild, &child->children, link) { | 1124 | wl_list_for_each_safe(subchild, tmpchild, &child->children, link) { |
1082 | wl_list_remove(&subchild->link); | 1125 | wl_list_remove(&subchild->link); |
1083 | subchild->parent = NULL; | 1126 | subchild->parent = NULL; |
1127 | // The subchild lost its parent link, so it cannot see that the parent | ||
1128 | // is unmapped. Unmap it directly. | ||
1129 | subchild->mapped = false; | ||
1084 | } | 1130 | } |
1085 | 1131 | ||
1086 | wl_list_remove(&child->surface_commit.link); | 1132 | wl_list_remove(&child->surface_commit.link); |
@@ -1101,18 +1147,27 @@ struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) { | |||
1101 | if (wlr_surface_is_xdg_surface(wlr_surface)) { | 1147 | if (wlr_surface_is_xdg_surface(wlr_surface)) { |
1102 | struct wlr_xdg_surface *xdg_surface = | 1148 | struct wlr_xdg_surface *xdg_surface = |
1103 | wlr_xdg_surface_from_wlr_surface(wlr_surface); | 1149 | wlr_xdg_surface_from_wlr_surface(wlr_surface); |
1150 | if (xdg_surface == NULL) { | ||
1151 | return NULL; | ||
1152 | } | ||
1104 | return view_from_wlr_xdg_surface(xdg_surface); | 1153 | return view_from_wlr_xdg_surface(xdg_surface); |
1105 | } | 1154 | } |
1106 | #if HAVE_XWAYLAND | 1155 | #if HAVE_XWAYLAND |
1107 | if (wlr_surface_is_xwayland_surface(wlr_surface)) { | 1156 | if (wlr_surface_is_xwayland_surface(wlr_surface)) { |
1108 | struct wlr_xwayland_surface *xsurface = | 1157 | struct wlr_xwayland_surface *xsurface = |
1109 | wlr_xwayland_surface_from_wlr_surface(wlr_surface); | 1158 | wlr_xwayland_surface_from_wlr_surface(wlr_surface); |
1159 | if (xsurface == NULL) { | ||
1160 | return NULL; | ||
1161 | } | ||
1110 | return view_from_wlr_xwayland_surface(xsurface); | 1162 | return view_from_wlr_xwayland_surface(xsurface); |
1111 | } | 1163 | } |
1112 | #endif | 1164 | #endif |
1113 | if (wlr_surface_is_subsurface(wlr_surface)) { | 1165 | if (wlr_surface_is_subsurface(wlr_surface)) { |
1114 | struct wlr_subsurface *subsurface = | 1166 | struct wlr_subsurface *subsurface = |
1115 | wlr_subsurface_from_wlr_surface(wlr_surface); | 1167 | wlr_subsurface_from_wlr_surface(wlr_surface); |
1168 | if (subsurface == NULL) { | ||
1169 | return NULL; | ||
1170 | } | ||
1116 | return view_from_wlr_surface(subsurface->parent); | 1171 | return view_from_wlr_surface(subsurface->parent); |
1117 | } | 1172 | } |
1118 | if (wlr_surface_is_layer_surface(wlr_surface)) { | 1173 | if (wlr_surface_is_layer_surface(wlr_surface)) { |
@@ -1225,8 +1280,6 @@ void view_update_title(struct sway_view *view, bool force) { | |||
1225 | view->container->title = NULL; | 1280 | view->container->title = NULL; |
1226 | view->container->formatted_title = NULL; | 1281 | view->container->formatted_title = NULL; |
1227 | } | 1282 | } |
1228 | container_calculate_title_height(view->container); | ||
1229 | config_update_font_height(false); | ||
1230 | 1283 | ||
1231 | // Update title after the global font height is updated | 1284 | // Update title after the global font height is updated |
1232 | container_update_title_textures(view->container); | 1285 | container_update_title_textures(view->container); |
@@ -1242,15 +1295,15 @@ bool view_is_visible(struct sway_view *view) { | |||
1242 | if (view->container->node.destroying) { | 1295 | if (view->container->node.destroying) { |
1243 | return false; | 1296 | return false; |
1244 | } | 1297 | } |
1245 | struct sway_workspace *workspace = view->container->workspace; | 1298 | struct sway_workspace *workspace = view->container->pending.workspace; |
1246 | if (!workspace && view->container->fullscreen_mode != FULLSCREEN_GLOBAL) { | 1299 | if (!workspace && view->container->pending.fullscreen_mode != FULLSCREEN_GLOBAL) { |
1247 | bool fs_global_descendant = false; | 1300 | bool fs_global_descendant = false; |
1248 | struct sway_container *parent = view->container->parent; | 1301 | struct sway_container *parent = view->container->pending.parent; |
1249 | while (parent) { | 1302 | while (parent) { |
1250 | if (parent->fullscreen_mode == FULLSCREEN_GLOBAL) { | 1303 | if (parent->pending.fullscreen_mode == FULLSCREEN_GLOBAL) { |
1251 | fs_global_descendant = true; | 1304 | fs_global_descendant = true; |
1252 | } | 1305 | } |
1253 | parent = parent->parent; | 1306 | parent = parent->pending.parent; |
1254 | } | 1307 | } |
1255 | if (!fs_global_descendant) { | 1308 | if (!fs_global_descendant) { |
1256 | return false; | 1309 | return false; |
@@ -1268,13 +1321,13 @@ bool view_is_visible(struct sway_view *view) { | |||
1268 | enum sway_container_layout layout = container_parent_layout(con); | 1321 | enum sway_container_layout layout = container_parent_layout(con); |
1269 | if ((layout == L_TABBED || layout == L_STACKED) | 1322 | if ((layout == L_TABBED || layout == L_STACKED) |
1270 | && !container_is_floating(con)) { | 1323 | && !container_is_floating(con)) { |
1271 | struct sway_node *parent = con->parent ? | 1324 | struct sway_node *parent = con->pending.parent ? |
1272 | &con->parent->node : &con->workspace->node; | 1325 | &con->pending.parent->node : &con->pending.workspace->node; |
1273 | if (seat_get_active_tiling_child(seat, parent) != &con->node) { | 1326 | if (seat_get_active_tiling_child(seat, parent) != &con->node) { |
1274 | return false; | 1327 | return false; |
1275 | } | 1328 | } |
1276 | } | 1329 | } |
1277 | con = con->parent; | 1330 | con = con->pending.parent; |
1278 | } | 1331 | } |
1279 | // Check view isn't hidden by another fullscreen view | 1332 | // Check view isn't hidden by another fullscreen view |
1280 | struct sway_container *fs = root->fullscreen_global ? | 1333 | struct sway_container *fs = root->fullscreen_global ? |
@@ -1308,7 +1361,7 @@ void view_set_urgent(struct sway_view *view, bool enable) { | |||
1308 | ipc_event_window(view->container, "urgent"); | 1361 | ipc_event_window(view->container, "urgent"); |
1309 | 1362 | ||
1310 | if (!container_is_scratchpad_hidden(view->container)) { | 1363 | if (!container_is_scratchpad_hidden(view->container)) { |
1311 | workspace_detect_urgent(view->container->workspace); | 1364 | workspace_detect_urgent(view->container->pending.workspace); |
1312 | } | 1365 | } |
1313 | } | 1366 | } |
1314 | 1367 | ||
@@ -1338,11 +1391,11 @@ static void view_save_buffer_iterator(struct wlr_surface *surface, | |||
1338 | saved_buffer->buffer = surface->buffer; | 1391 | saved_buffer->buffer = surface->buffer; |
1339 | saved_buffer->width = surface->current.width; | 1392 | saved_buffer->width = surface->current.width; |
1340 | saved_buffer->height = surface->current.height; | 1393 | saved_buffer->height = surface->current.height; |
1341 | saved_buffer->x = sx; | 1394 | saved_buffer->x = view->container->surface_x + sx; |
1342 | saved_buffer->y = sy; | 1395 | saved_buffer->y = view->container->surface_y + sy; |
1343 | saved_buffer->transform = surface->current.transform; | 1396 | saved_buffer->transform = surface->current.transform; |
1344 | wlr_surface_get_buffer_source_box(surface, &saved_buffer->source_box); | 1397 | wlr_surface_get_buffer_source_box(surface, &saved_buffer->source_box); |
1345 | wl_list_insert(&view->saved_buffers, &saved_buffer->link); | 1398 | wl_list_insert(view->saved_buffers.prev, &saved_buffer->link); |
1346 | } | 1399 | } |
1347 | } | 1400 | } |
1348 | 1401 | ||
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index 921b7d19..8dd7789d 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c | |||
@@ -48,7 +48,7 @@ struct sway_output *workspace_get_initial_output(const char *name) { | |||
48 | if (focus && focus->type == N_WORKSPACE) { | 48 | if (focus && focus->type == N_WORKSPACE) { |
49 | return focus->sway_workspace->output; | 49 | return focus->sway_workspace->output; |
50 | } else if (focus && focus->type == N_CONTAINER) { | 50 | } else if (focus && focus->type == N_CONTAINER) { |
51 | return focus->sway_container->workspace->output; | 51 | return focus->sway_container->pending.workspace->output; |
52 | } | 52 | } |
53 | // Fallback to the first output or noop output for headless | 53 | // Fallback to the first output or noop output for headless |
54 | return root->outputs->length ? root->outputs->items[0] : root->noop_output; | 54 | return root->outputs->length ? root->outputs->items[0] : root->noop_output; |
@@ -222,10 +222,8 @@ static void workspace_name_from_binding(const struct sway_binding * binding, | |||
222 | // not a command about workspaces | 222 | // not a command about workspaces |
223 | if (strcmp(_target, "next") == 0 || | 223 | if (strcmp(_target, "next") == 0 || |
224 | strcmp(_target, "prev") == 0 || | 224 | strcmp(_target, "prev") == 0 || |
225 | strncmp(_target, "next_on_output", | 225 | strcmp(_target, "next_on_output") == 0 || |
226 | strlen("next_on_output")) == 0 || | 226 | strcmp(_target, "prev_on_output") == 0 || |
227 | strncmp(_target, "prev_on_output", | ||
228 | strlen("next_on_output")) == 0 || | ||
229 | strcmp(_target, "number") == 0 || | 227 | strcmp(_target, "number") == 0 || |
230 | strcmp(_target, "back_and_forth") == 0 || | 228 | strcmp(_target, "back_and_forth") == 0 || |
231 | strcmp(_target, "current") == 0) { | 229 | strcmp(_target, "current") == 0) { |
@@ -363,11 +361,11 @@ struct sway_workspace *workspace_by_name(const char *name) { | |||
363 | if (current && strcmp(name, "prev") == 0) { | 361 | if (current && strcmp(name, "prev") == 0) { |
364 | return workspace_prev(current); | 362 | return workspace_prev(current); |
365 | } else if (current && strcmp(name, "prev_on_output") == 0) { | 363 | } else if (current && strcmp(name, "prev_on_output") == 0) { |
366 | return workspace_output_prev(current, false); | 364 | return workspace_output_prev(current); |
367 | } else if (current && strcmp(name, "next") == 0) { | 365 | } else if (current && strcmp(name, "next") == 0) { |
368 | return workspace_next(current); | 366 | return workspace_next(current); |
369 | } else if (current && strcmp(name, "next_on_output") == 0) { | 367 | } else if (current && strcmp(name, "next_on_output") == 0) { |
370 | return workspace_output_next(current, false); | 368 | return workspace_output_next(current); |
371 | } else if (strcmp(name, "current") == 0) { | 369 | } else if (strcmp(name, "current") == 0) { |
372 | return current; | 370 | return current; |
373 | } else if (strcasecmp(name, "back_and_forth") == 0) { | 371 | } else if (strcasecmp(name, "back_and_forth") == 0) { |
@@ -530,7 +528,7 @@ struct sway_workspace *workspace_next(struct sway_workspace *workspace) { | |||
530 | * otherwise the next one is returned. | 528 | * otherwise the next one is returned. |
531 | */ | 529 | */ |
532 | static struct sway_workspace *workspace_output_prev_next_impl( | 530 | static struct sway_workspace *workspace_output_prev_next_impl( |
533 | struct sway_output *output, int dir, bool create) { | 531 | struct sway_output *output, int dir) { |
534 | struct sway_seat *seat = input_manager_current_seat(); | 532 | struct sway_seat *seat = input_manager_current_seat(); |
535 | struct sway_workspace *workspace = seat_get_focused_workspace(seat); | 533 | struct sway_workspace *workspace = seat_get_focused_workspace(seat); |
536 | if (!workspace) { | 534 | if (!workspace) { |
@@ -540,46 +538,43 @@ static struct sway_workspace *workspace_output_prev_next_impl( | |||
540 | } | 538 | } |
541 | 539 | ||
542 | int index = list_find(output->workspaces, workspace); | 540 | int index = list_find(output->workspaces, workspace); |
543 | if (!workspace_is_empty(workspace) && create && | ||
544 | (index + dir < 0 || index + dir == output->workspaces->length)) { | ||
545 | struct sway_output *output = workspace->output; | ||
546 | char *next = workspace_next_name(output->wlr_output->name); | ||
547 | workspace_create(output, next); | ||
548 | free(next); | ||
549 | } | ||
550 | size_t new_index = wrap(index + dir, output->workspaces->length); | 541 | size_t new_index = wrap(index + dir, output->workspaces->length); |
551 | return output->workspaces->items[new_index]; | 542 | return output->workspaces->items[new_index]; |
552 | } | 543 | } |
553 | 544 | ||
554 | struct sway_workspace *workspace_output_next( | 545 | |
555 | struct sway_workspace *current, bool create) { | 546 | struct sway_workspace *workspace_output_next(struct sway_workspace *current) { |
556 | return workspace_output_prev_next_impl(current->output, 1, create); | 547 | return workspace_output_prev_next_impl(current->output, 1); |
557 | } | 548 | } |
558 | 549 | ||
559 | struct sway_workspace *workspace_output_prev( | 550 | struct sway_workspace *workspace_output_prev(struct sway_workspace *current) { |
560 | struct sway_workspace *current, bool create) { | 551 | return workspace_output_prev_next_impl(current->output, -1); |
561 | return workspace_output_prev_next_impl(current->output, -1, create); | ||
562 | } | 552 | } |
563 | 553 | ||
564 | bool workspace_switch(struct sway_workspace *workspace, | 554 | struct sway_workspace *workspace_auto_back_and_forth( |
565 | bool no_auto_back_and_forth) { | 555 | struct sway_workspace *workspace) { |
566 | struct sway_seat *seat = input_manager_current_seat(); | 556 | struct sway_seat *seat = input_manager_current_seat(); |
567 | struct sway_workspace *active_ws = NULL; | 557 | struct sway_workspace *active_ws = NULL; |
568 | struct sway_node *focus = seat_get_focus_inactive(seat, &root->node); | 558 | struct sway_node *focus = seat_get_focus_inactive(seat, &root->node); |
569 | if (focus && focus->type == N_WORKSPACE) { | 559 | if (focus && focus->type == N_WORKSPACE) { |
570 | active_ws = focus->sway_workspace; | 560 | active_ws = focus->sway_workspace; |
571 | } else if (focus && focus->type == N_CONTAINER) { | 561 | } else if (focus && focus->type == N_CONTAINER) { |
572 | active_ws = focus->sway_container->workspace; | 562 | active_ws = focus->sway_container->pending.workspace; |
573 | } | 563 | } |
574 | 564 | ||
575 | if (!no_auto_back_and_forth && config->auto_back_and_forth && active_ws | 565 | if (config->auto_back_and_forth && active_ws && active_ws == workspace && |
576 | && active_ws == workspace && seat->prev_workspace_name) { | 566 | seat->prev_workspace_name) { |
577 | struct sway_workspace *new_ws = | 567 | struct sway_workspace *new_ws = |
578 | workspace_by_name(seat->prev_workspace_name); | 568 | workspace_by_name(seat->prev_workspace_name); |
579 | workspace = new_ws ? | 569 | workspace = new_ws ? |
580 | new_ws : | 570 | new_ws : |
581 | workspace_create(NULL, seat->prev_workspace_name); | 571 | workspace_create(NULL, seat->prev_workspace_name); |
582 | } | 572 | } |
573 | return workspace; | ||
574 | } | ||
575 | |||
576 | bool workspace_switch(struct sway_workspace *workspace) { | ||
577 | struct sway_seat *seat = input_manager_current_seat(); | ||
583 | 578 | ||
584 | sway_log(SWAY_DEBUG, "Switching to workspace %p:%s", | 579 | sway_log(SWAY_DEBUG, "Switching to workspace %p:%s", |
585 | workspace, workspace->name); | 580 | workspace, workspace->name); |
@@ -736,13 +731,13 @@ struct sway_container *workspace_find_container(struct sway_workspace *ws, | |||
736 | } | 731 | } |
737 | 732 | ||
738 | static void set_workspace(struct sway_container *container, void *data) { | 733 | static void set_workspace(struct sway_container *container, void *data) { |
739 | container->workspace = container->parent->workspace; | 734 | container->pending.workspace = container->pending.parent->pending.workspace; |
740 | } | 735 | } |
741 | 736 | ||
742 | static void workspace_attach_tiling(struct sway_workspace *ws, | 737 | static void workspace_attach_tiling(struct sway_workspace *ws, |
743 | struct sway_container *con) { | 738 | struct sway_container *con) { |
744 | list_add(ws->tiling, con); | 739 | list_add(ws->tiling, con); |
745 | con->workspace = ws; | 740 | con->pending.workspace = ws; |
746 | container_for_each_child(con, set_workspace, NULL); | 741 | container_for_each_child(con, set_workspace, NULL); |
747 | container_handle_fullscreen_reparent(con); | 742 | container_handle_fullscreen_reparent(con); |
748 | workspace_update_representation(ws); | 743 | workspace_update_representation(ws); |
@@ -753,7 +748,7 @@ static void workspace_attach_tiling(struct sway_workspace *ws, | |||
753 | struct sway_container *workspace_wrap_children(struct sway_workspace *ws) { | 748 | struct sway_container *workspace_wrap_children(struct sway_workspace *ws) { |
754 | struct sway_container *fs = ws->fullscreen; | 749 | struct sway_container *fs = ws->fullscreen; |
755 | struct sway_container *middle = container_create(NULL); | 750 | struct sway_container *middle = container_create(NULL); |
756 | middle->layout = ws->layout; | 751 | middle->pending.layout = ws->layout; |
757 | while (ws->tiling->length) { | 752 | while (ws->tiling->length) { |
758 | struct sway_container *child = ws->tiling->items[0]; | 753 | struct sway_container *child = ws->tiling->items[0]; |
759 | container_detach(child); | 754 | container_detach(child); |
@@ -771,9 +766,9 @@ void workspace_unwrap_children(struct sway_workspace *ws, | |||
771 | return; | 766 | return; |
772 | } | 767 | } |
773 | 768 | ||
774 | ws->layout = wrap->layout; | 769 | ws->layout = wrap->pending.layout; |
775 | while (wrap->children->length) { | 770 | while (wrap->pending.children->length) { |
776 | struct sway_container *child = wrap->children->items[0]; | 771 | struct sway_container *child = wrap->pending.children->items[0]; |
777 | container_detach(child); | 772 | container_detach(child); |
778 | workspace_add_tiling(ws, child); | 773 | workspace_add_tiling(ws, child); |
779 | } | 774 | } |
@@ -793,14 +788,18 @@ void workspace_detach(struct sway_workspace *workspace) { | |||
793 | 788 | ||
794 | struct sway_container *workspace_add_tiling(struct sway_workspace *workspace, | 789 | struct sway_container *workspace_add_tiling(struct sway_workspace *workspace, |
795 | struct sway_container *con) { | 790 | struct sway_container *con) { |
796 | if (con->workspace) { | 791 | if (con->pending.workspace) { |
792 | struct sway_container *old_parent = con->pending.parent; | ||
797 | container_detach(con); | 793 | container_detach(con); |
794 | if (old_parent) { | ||
795 | container_reap_empty(old_parent); | ||
796 | } | ||
798 | } | 797 | } |
799 | if (config->default_layout != L_NONE) { | 798 | if (config->default_layout != L_NONE) { |
800 | con = container_split(con, config->default_layout); | 799 | con = container_split(con, config->default_layout); |
801 | } | 800 | } |
802 | list_add(workspace->tiling, con); | 801 | list_add(workspace->tiling, con); |
803 | con->workspace = workspace; | 802 | con->pending.workspace = workspace; |
804 | container_for_each_child(con, set_workspace, NULL); | 803 | container_for_each_child(con, set_workspace, NULL); |
805 | container_handle_fullscreen_reparent(con); | 804 | container_handle_fullscreen_reparent(con); |
806 | workspace_update_representation(workspace); | 805 | workspace_update_representation(workspace); |
@@ -811,11 +810,11 @@ struct sway_container *workspace_add_tiling(struct sway_workspace *workspace, | |||
811 | 810 | ||
812 | void workspace_add_floating(struct sway_workspace *workspace, | 811 | void workspace_add_floating(struct sway_workspace *workspace, |
813 | struct sway_container *con) { | 812 | struct sway_container *con) { |
814 | if (con->workspace) { | 813 | if (con->pending.workspace) { |
815 | container_detach(con); | 814 | container_detach(con); |
816 | } | 815 | } |
817 | list_add(workspace->floating, con); | 816 | list_add(workspace->floating, con); |
818 | con->workspace = workspace; | 817 | con->pending.workspace = workspace; |
819 | container_for_each_child(con, set_workspace, NULL); | 818 | container_for_each_child(con, set_workspace, NULL); |
820 | container_handle_fullscreen_reparent(con); | 819 | container_handle_fullscreen_reparent(con); |
821 | node_set_dirty(&workspace->node); | 820 | node_set_dirty(&workspace->node); |
@@ -825,7 +824,7 @@ void workspace_add_floating(struct sway_workspace *workspace, | |||
825 | void workspace_insert_tiling_direct(struct sway_workspace *workspace, | 824 | void workspace_insert_tiling_direct(struct sway_workspace *workspace, |
826 | struct sway_container *con, int index) { | 825 | struct sway_container *con, int index) { |
827 | list_insert(workspace->tiling, index, con); | 826 | list_insert(workspace->tiling, index, con); |
828 | con->workspace = workspace; | 827 | con->pending.workspace = workspace; |
829 | container_for_each_child(con, set_workspace, NULL); | 828 | container_for_each_child(con, set_workspace, NULL); |
830 | container_handle_fullscreen_reparent(con); | 829 | container_handle_fullscreen_reparent(con); |
831 | workspace_update_representation(workspace); | 830 | workspace_update_representation(workspace); |
@@ -835,7 +834,7 @@ void workspace_insert_tiling_direct(struct sway_workspace *workspace, | |||
835 | 834 | ||
836 | struct sway_container *workspace_insert_tiling(struct sway_workspace *workspace, | 835 | struct sway_container *workspace_insert_tiling(struct sway_workspace *workspace, |
837 | struct sway_container *con, int index) { | 836 | struct sway_container *con, int index) { |
838 | if (con->workspace) { | 837 | if (con->pending.workspace) { |
839 | container_detach(con); | 838 | container_detach(con); |
840 | } | 839 | } |
841 | if (config->default_layout != L_NONE) { | 840 | if (config->default_layout != L_NONE) { |
@@ -905,7 +904,7 @@ struct sway_container *workspace_split(struct sway_workspace *workspace, | |||
905 | enum sway_container_layout old_layout = workspace->layout; | 904 | enum sway_container_layout old_layout = workspace->layout; |
906 | struct sway_container *middle = workspace_wrap_children(workspace); | 905 | struct sway_container *middle = workspace_wrap_children(workspace); |
907 | workspace->layout = layout; | 906 | workspace->layout = layout; |
908 | middle->layout = old_layout; | 907 | middle->pending.layout = old_layout; |
909 | 908 | ||
910 | struct sway_seat *seat; | 909 | struct sway_seat *seat; |
911 | wl_list_for_each(seat, &server.input->seats, link) { | 910 | wl_list_for_each(seat, &server.input->seats, link) { |
diff --git a/sway/xdg_activation_v1.c b/sway/xdg_activation_v1.c new file mode 100644 index 00000000..6c70c785 --- /dev/null +++ b/sway/xdg_activation_v1.c | |||
@@ -0,0 +1,20 @@ | |||
1 | #include <wlr/types/wlr_xdg_activation_v1.h> | ||
2 | #include "sway/tree/view.h" | ||
3 | |||
4 | void xdg_activation_v1_handle_request_activate(struct wl_listener *listener, | ||
5 | void *data) { | ||
6 | const struct wlr_xdg_activation_v1_request_activate_event *event = data; | ||
7 | |||
8 | if (!wlr_surface_is_xdg_surface(event->surface)) { | ||
9 | return; | ||
10 | } | ||
11 | |||
12 | struct wlr_xdg_surface *xdg_surface = | ||
13 | wlr_xdg_surface_from_wlr_surface(event->surface); | ||
14 | struct sway_view *view = xdg_surface->data; | ||
15 | if (!xdg_surface->mapped || view == NULL) { | ||
16 | return; | ||
17 | } | ||
18 | |||
19 | view_request_activate(view); | ||
20 | } | ||
diff --git a/sway/xdg_decoration.c b/sway/xdg_decoration.c index e7c3ea73..ec9e8d68 100644 --- a/sway/xdg_decoration.c +++ b/sway/xdg_decoration.c | |||
@@ -10,7 +10,7 @@ static void xdg_decoration_handle_destroy(struct wl_listener *listener, | |||
10 | void *data) { | 10 | void *data) { |
11 | struct sway_xdg_decoration *deco = | 11 | struct sway_xdg_decoration *deco = |
12 | wl_container_of(listener, deco, destroy); | 12 | wl_container_of(listener, deco, destroy); |
13 | if(deco->view) { | 13 | if (deco->view) { |
14 | deco->view->xdg_decoration = NULL; | 14 | deco->view->xdg_decoration = NULL; |
15 | } | 15 | } |
16 | wl_list_remove(&deco->destroy.link); | 16 | wl_list_remove(&deco->destroy.link); |
@@ -23,8 +23,32 @@ static void xdg_decoration_handle_request_mode(struct wl_listener *listener, | |||
23 | void *data) { | 23 | void *data) { |
24 | struct sway_xdg_decoration *deco = | 24 | struct sway_xdg_decoration *deco = |
25 | wl_container_of(listener, deco, request_mode); | 25 | wl_container_of(listener, deco, request_mode); |
26 | struct sway_view *view = deco->view; | ||
27 | enum wlr_xdg_toplevel_decoration_v1_mode mode = | ||
28 | WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE; | ||
29 | enum wlr_xdg_toplevel_decoration_v1_mode client_mode = | ||
30 | deco->wlr_xdg_decoration->requested_mode; | ||
31 | |||
32 | bool floating; | ||
33 | if (view->container) { | ||
34 | floating = container_is_floating(view->container); | ||
35 | bool csd = false; | ||
36 | csd = client_mode == | ||
37 | WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_CLIENT_SIDE; | ||
38 | view_update_csd_from_client(view, csd); | ||
39 | arrange_container(view->container); | ||
40 | transaction_commit_dirty(); | ||
41 | } else { | ||
42 | floating = view->impl->wants_floating && | ||
43 | view->impl->wants_floating(view); | ||
44 | } | ||
45 | |||
46 | if (floating && client_mode) { | ||
47 | mode = client_mode; | ||
48 | } | ||
49 | |||
26 | wlr_xdg_toplevel_decoration_v1_set_mode(deco->wlr_xdg_decoration, | 50 | wlr_xdg_toplevel_decoration_v1_set_mode(deco->wlr_xdg_decoration, |
27 | WLR_XDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE); | 51 | mode); |
28 | } | 52 | } |
29 | 53 | ||
30 | void handle_xdg_decoration(struct wl_listener *listener, void *data) { | 54 | void handle_xdg_decoration(struct wl_listener *listener, void *data) { |
diff --git a/swaybar/bar.c b/swaybar/bar.c index 231c1ad7..15eab782 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c | |||
@@ -90,7 +90,7 @@ static void layer_surface_closed(void *_output, | |||
90 | swaybar_output_free(output); | 90 | swaybar_output_free(output); |
91 | } | 91 | } |
92 | 92 | ||
93 | struct zwlr_layer_surface_v1_listener layer_surface_listener = { | 93 | static const struct zwlr_layer_surface_v1_listener layer_surface_listener = { |
94 | .configure = layer_surface_configure, | 94 | .configure = layer_surface_configure, |
95 | .closed = layer_surface_closed, | 95 | .closed = layer_surface_closed, |
96 | }; | 96 | }; |
@@ -230,7 +230,7 @@ static void output_scale(void *data, struct wl_output *wl_output, | |||
230 | } | 230 | } |
231 | } | 231 | } |
232 | 232 | ||
233 | struct wl_output_listener output_listener = { | 233 | static const struct wl_output_listener output_listener = { |
234 | .geometry = output_geometry, | 234 | .geometry = output_geometry, |
235 | .mode = output_mode, | 235 | .mode = output_mode, |
236 | .done = output_done, | 236 | .done = output_done, |
@@ -307,7 +307,7 @@ static void xdg_output_handle_description(void *data, | |||
307 | } | 307 | } |
308 | } | 308 | } |
309 | 309 | ||
310 | struct zxdg_output_v1_listener xdg_output_listener = { | 310 | static const struct zxdg_output_v1_listener xdg_output_listener = { |
311 | .logical_position = xdg_output_handle_logical_position, | 311 | .logical_position = xdg_output_handle_logical_position, |
312 | .logical_size = xdg_output_handle_logical_size, | 312 | .logical_size = xdg_output_handle_logical_size, |
313 | .done = xdg_output_handle_done, | 313 | .done = xdg_output_handle_done, |
@@ -461,13 +461,28 @@ bool bar_setup(struct swaybar *bar, const char *socket_path) { | |||
461 | 461 | ||
462 | static void display_in(int fd, short mask, void *data) { | 462 | static void display_in(int fd, short mask, void *data) { |
463 | struct swaybar *bar = data; | 463 | struct swaybar *bar = data; |
464 | if (mask & (POLLHUP | POLLERR)) { | ||
465 | if (mask & POLLERR) { | ||
466 | sway_log(SWAY_ERROR, "Wayland display poll error"); | ||
467 | } | ||
468 | bar->running = false; | ||
469 | return; | ||
470 | } | ||
464 | if (wl_display_dispatch(bar->display) == -1) { | 471 | if (wl_display_dispatch(bar->display) == -1) { |
472 | sway_log(SWAY_ERROR, "wl_display_dispatch failed"); | ||
465 | bar->running = false; | 473 | bar->running = false; |
466 | } | 474 | } |
467 | } | 475 | } |
468 | 476 | ||
469 | static void ipc_in(int fd, short mask, void *data) { | 477 | static void ipc_in(int fd, short mask, void *data) { |
470 | struct swaybar *bar = data; | 478 | struct swaybar *bar = data; |
479 | if (mask & (POLLHUP | POLLERR)) { | ||
480 | if (mask & POLLERR) { | ||
481 | sway_log(SWAY_ERROR, "IPC poll error"); | ||
482 | } | ||
483 | bar->running = false; | ||
484 | return; | ||
485 | } | ||
471 | if (handle_ipc_readable(bar)) { | 486 | if (handle_ipc_readable(bar)) { |
472 | set_bar_dirty(bar); | 487 | set_bar_dirty(bar); |
473 | } | 488 | } |
diff --git a/swaybar/i3bar.c b/swaybar/i3bar.c index 4bcd5843..6d00befb 100644 --- a/swaybar/i3bar.c +++ b/swaybar/i3bar.c | |||
@@ -28,6 +28,19 @@ void i3bar_block_unref(struct i3bar_block *block) { | |||
28 | } | 28 | } |
29 | } | 29 | } |
30 | 30 | ||
31 | static bool i3bar_parse_json_color(json_object *json, uint32_t *color) { | ||
32 | if (!json) { | ||
33 | return false; | ||
34 | } | ||
35 | |||
36 | const char *hexstring = json_object_get_string(json); | ||
37 | bool color_set = parse_color(hexstring, color); | ||
38 | if (!color_set) { | ||
39 | sway_log(SWAY_ERROR, "Ignoring invalid block hexadecimal color string: %s", hexstring); | ||
40 | } | ||
41 | return color_set; | ||
42 | } | ||
43 | |||
31 | static void i3bar_parse_json(struct status_line *status, | 44 | static void i3bar_parse_json(struct status_line *status, |
32 | struct json_object *json_array) { | 45 | struct json_object *json_array) { |
33 | struct i3bar_block *block, *tmp; | 46 | struct i3bar_block *block, *tmp; |
@@ -68,13 +81,7 @@ static void i3bar_parse_json(struct status_line *status, | |||
68 | strdup(json_object_get_string(full_text)) : NULL; | 81 | strdup(json_object_get_string(full_text)) : NULL; |
69 | block->short_text = short_text ? | 82 | block->short_text = short_text ? |
70 | strdup(json_object_get_string(short_text)) : NULL; | 83 | strdup(json_object_get_string(short_text)) : NULL; |
71 | if (color) { | 84 | block->color_set = i3bar_parse_json_color(color, &block->color); |
72 | const char *hexstring = json_object_get_string(color); | ||
73 | block->color_set = parse_color(hexstring, &block->color); | ||
74 | if (!block->color_set) { | ||
75 | sway_log(SWAY_ERROR, "Invalid block color: %s", hexstring); | ||
76 | } | ||
77 | } | ||
78 | if (min_width) { | 85 | if (min_width) { |
79 | json_type type = json_object_get_type(min_width); | 86 | json_type type = json_object_get_type(min_width); |
80 | if (type == json_type_int) { | 87 | if (type == json_type_int) { |
@@ -100,14 +107,8 @@ static void i3bar_parse_json(struct status_line *status, | |||
100 | block->separator_block_width = separator_block_width ? | 107 | block->separator_block_width = separator_block_width ? |
101 | json_object_get_int(separator_block_width) : 9; | 108 | json_object_get_int(separator_block_width) : 9; |
102 | // Airblader features | 109 | // Airblader features |
103 | const char *hex = background ? json_object_get_string(background) : NULL; | 110 | i3bar_parse_json_color(background, &block->background); |
104 | if (hex && !parse_color(hex, &block->background)) { | 111 | block->border_set = i3bar_parse_json_color(border, &block->border); |
105 | sway_log(SWAY_ERROR, "Ignoring invalid block background: %s", hex); | ||
106 | } | ||
107 | hex = border ? json_object_get_string(border) : NULL; | ||
108 | if (hex && !parse_color(hex, &block->border)) { | ||
109 | sway_log(SWAY_ERROR, "Ignoring invalid block border: %s", hex); | ||
110 | } | ||
111 | block->border_top = border_top ? json_object_get_int(border_top) : 1; | 112 | block->border_top = border_top ? json_object_get_int(border_top) : 1; |
112 | block->border_bottom = border_bottom ? | 113 | block->border_bottom = border_bottom ? |
113 | json_object_get_int(border_bottom) : 1; | 114 | json_object_get_int(border_bottom) : 1; |
diff --git a/swaybar/input.c b/swaybar/input.c index 4fe6dd93..c8c8f0d4 100644 --- a/swaybar/input.c +++ b/swaybar/input.c | |||
@@ -101,6 +101,8 @@ static void wl_pointer_enter(void *data, struct wl_pointer *wl_pointer, | |||
101 | wl_fixed_t surface_x, wl_fixed_t surface_y) { | 101 | wl_fixed_t surface_x, wl_fixed_t surface_y) { |
102 | struct swaybar_seat *seat = data; | 102 | struct swaybar_seat *seat = data; |
103 | struct swaybar_pointer *pointer = &seat->pointer; | 103 | struct swaybar_pointer *pointer = &seat->pointer; |
104 | seat->pointer.x = wl_fixed_to_double(surface_x); | ||
105 | seat->pointer.y = wl_fixed_to_double(surface_y); | ||
104 | pointer->serial = serial; | 106 | pointer->serial = serial; |
105 | struct swaybar_output *output; | 107 | struct swaybar_output *output; |
106 | wl_list_for_each(output, &seat->bar->outputs, link) { | 108 | wl_list_for_each(output, &seat->bar->outputs, link) { |
@@ -140,13 +142,11 @@ static bool check_bindings(struct swaybar *bar, uint32_t button, | |||
140 | 142 | ||
141 | static bool process_hotspots(struct swaybar_output *output, | 143 | static bool process_hotspots(struct swaybar_output *output, |
142 | double x, double y, uint32_t button) { | 144 | double x, double y, uint32_t button) { |
143 | double px = x * output->scale; | ||
144 | double py = y * output->scale; | ||
145 | struct swaybar_hotspot *hotspot; | 145 | struct swaybar_hotspot *hotspot; |
146 | wl_list_for_each(hotspot, &output->hotspots, link) { | 146 | wl_list_for_each(hotspot, &output->hotspots, link) { |
147 | if (px >= hotspot->x && py >= hotspot->y | 147 | if (x >= hotspot->x && y >= hotspot->y |
148 | && px < hotspot->x + hotspot->width | 148 | && x < hotspot->x + hotspot->width |
149 | && py < hotspot->y + hotspot->height) { | 149 | && y < hotspot->y + hotspot->height) { |
150 | if (HOTSPOT_IGNORE == hotspot->callback(output, hotspot, x, y, | 150 | if (HOTSPOT_IGNORE == hotspot->callback(output, hotspot, x, y, |
151 | button, hotspot->data)) { | 151 | button, hotspot->data)) { |
152 | return true; | 152 | return true; |
@@ -339,7 +339,7 @@ static void wl_pointer_axis_discrete(void *data, struct wl_pointer *wl_pointer, | |||
339 | seat->axis[axis].discrete_steps += abs(discrete); | 339 | seat->axis[axis].discrete_steps += abs(discrete); |
340 | } | 340 | } |
341 | 341 | ||
342 | static struct wl_pointer_listener pointer_listener = { | 342 | static const struct wl_pointer_listener pointer_listener = { |
343 | .enter = wl_pointer_enter, | 343 | .enter = wl_pointer_enter, |
344 | .leave = wl_pointer_leave, | 344 | .leave = wl_pointer_leave, |
345 | .motion = wl_pointer_motion, | 345 | .motion = wl_pointer_motion, |
diff --git a/swaybar/ipc.c b/swaybar/ipc.c index 6bbe9408..a64aa1ab 100644 --- a/swaybar/ipc.c +++ b/swaybar/ipc.c | |||
@@ -547,9 +547,23 @@ bool handle_ipc_readable(struct swaybar *bar) { | |||
547 | return false; | 547 | return false; |
548 | } | 548 | } |
549 | 549 | ||
550 | json_object *result = json_tokener_parse(resp->payload); | 550 | // The default depth of 32 is too small to represent some nested layouts, but |
551 | if (!result) { | 551 | // we can't pass INT_MAX here because json-c (as of this writing) prefaults |
552 | sway_log(SWAY_ERROR, "failed to parse payload as json"); | 552 | // all the memory for its stack. |
553 | json_tokener *tok = json_tokener_new_ex(256); | ||
554 | if (!tok) { | ||
555 | sway_log_errno(SWAY_ERROR, "failed to create tokener"); | ||
556 | free_ipc_response(resp); | ||
557 | return false; | ||
558 | } | ||
559 | |||
560 | json_object *result = json_tokener_parse_ex(tok, resp->payload, -1); | ||
561 | enum json_tokener_error err = json_tokener_get_error(tok); | ||
562 | json_tokener_free(tok); | ||
563 | |||
564 | if (err != json_tokener_success) { | ||
565 | sway_log(SWAY_ERROR, "failed to parse payload as json: %s", | ||
566 | json_tokener_error_desc(err)); | ||
553 | free_ipc_response(resp); | 567 | free_ipc_response(resp); |
554 | return false; | 568 | return false; |
555 | } | 569 | } |
diff --git a/swaybar/main.c b/swaybar/main.c index 5c36d66b..a44c1e63 100644 --- a/swaybar/main.c +++ b/swaybar/main.c | |||
@@ -18,7 +18,7 @@ int main(int argc, char **argv) { | |||
18 | char *socket_path = NULL; | 18 | char *socket_path = NULL; |
19 | bool debug = false; | 19 | bool debug = false; |
20 | 20 | ||
21 | static struct option long_options[] = { | 21 | static const struct option long_options[] = { |
22 | {"help", no_argument, NULL, 'h'}, | 22 | {"help", no_argument, NULL, 'h'}, |
23 | {"version", no_argument, NULL, 'v'}, | 23 | {"version", no_argument, NULL, 'v'}, |
24 | {"socket", required_argument, NULL, 's'}, | 24 | {"socket", required_argument, NULL, 's'}, |
diff --git a/swaybar/render.c b/swaybar/render.c index df066622..dcde6b9e 100644 --- a/swaybar/render.c +++ b/swaybar/render.c | |||
@@ -5,7 +5,7 @@ | |||
5 | #include <stdlib.h> | 5 | #include <stdlib.h> |
6 | #include <stdint.h> | 6 | #include <stdint.h> |
7 | #include <string.h> | 7 | #include <string.h> |
8 | #include "cairo.h" | 8 | #include "cairo_util.h" |
9 | #include "pango.h" | 9 | #include "pango.h" |
10 | #include "pool-buffer.h" | 10 | #include "pool-buffer.h" |
11 | #include "swaybar/bar.h" | 11 | #include "swaybar/bar.h" |
@@ -14,6 +14,7 @@ | |||
14 | #include "swaybar/ipc.h" | 14 | #include "swaybar/ipc.h" |
15 | #include "swaybar/render.h" | 15 | #include "swaybar/render.h" |
16 | #include "swaybar/status_line.h" | 16 | #include "swaybar/status_line.h" |
17 | #include "log.h" | ||
17 | #if HAVE_TRAY | 18 | #if HAVE_TRAY |
18 | #include "swaybar/tray/tray.h" | 19 | #include "swaybar/tray/tray.h" |
19 | #endif | 20 | #endif |
@@ -23,28 +24,51 @@ static const int WS_HORIZONTAL_PADDING = 5; | |||
23 | static const double WS_VERTICAL_PADDING = 1.5; | 24 | static const double WS_VERTICAL_PADDING = 1.5; |
24 | static const double BORDER_WIDTH = 1; | 25 | static const double BORDER_WIDTH = 1; |
25 | 26 | ||
26 | static uint32_t render_status_line_error(cairo_t *cairo, | 27 | struct render_context { |
27 | struct swaybar_output *output, double *x) { | 28 | cairo_t *cairo; |
29 | struct swaybar_output *output; | ||
30 | cairo_font_options_t *textaa_sharp; | ||
31 | cairo_font_options_t *textaa_safe; | ||
32 | uint32_t background_color; | ||
33 | }; | ||
34 | |||
35 | static void choose_text_aa_mode(struct render_context *ctx, uint32_t fontcolor) { | ||
36 | uint32_t salpha = fontcolor & 0xFF; | ||
37 | uint32_t balpha = ctx->background_color & 0xFF; | ||
38 | |||
39 | // Subpixel antialiasing requires blend be done in cairo, not compositor | ||
40 | cairo_font_options_t *fo = salpha == balpha ? | ||
41 | ctx->textaa_sharp : ctx->textaa_safe; | ||
42 | cairo_set_font_options(ctx->cairo, fo); | ||
43 | |||
44 | // Color emojis, being semitransparent bitmaps, are leaky with 'SOURCE' | ||
45 | cairo_operator_t op = salpha == 0xFF ? | ||
46 | CAIRO_OPERATOR_OVER : CAIRO_OPERATOR_SOURCE; | ||
47 | cairo_set_operator(ctx->cairo, op); | ||
48 | } | ||
49 | |||
50 | static uint32_t render_status_line_error(struct render_context *ctx, double *x) { | ||
51 | struct swaybar_output *output = ctx->output; | ||
28 | const char *error = output->bar->status->text; | 52 | const char *error = output->bar->status->text; |
29 | if (!error) { | 53 | if (!error) { |
30 | return 0; | 54 | return 0; |
31 | } | 55 | } |
32 | 56 | ||
33 | uint32_t height = output->height * output->scale; | 57 | uint32_t height = output->height; |
34 | 58 | ||
59 | cairo_t *cairo = ctx->cairo; | ||
35 | cairo_set_source_u32(cairo, 0xFF0000FF); | 60 | cairo_set_source_u32(cairo, 0xFF0000FF); |
36 | 61 | ||
37 | int margin = 3 * output->scale; | 62 | int margin = 3; |
38 | double ws_vertical_padding = | 63 | double ws_vertical_padding = output->bar->config->status_padding; |
39 | output->bar->config->status_padding * output->scale; | ||
40 | 64 | ||
41 | char *font = output->bar->config->font; | 65 | char *font = output->bar->config->font; |
42 | int text_width, text_height; | 66 | int text_width, text_height; |
43 | get_text_size(cairo, font, &text_width, &text_height, NULL, | 67 | get_text_size(cairo, font, &text_width, &text_height, NULL, |
44 | output->scale, false, "%s", error); | 68 | 1, false, "%s", error); |
45 | 69 | ||
46 | uint32_t ideal_height = text_height + ws_vertical_padding * 2; | 70 | uint32_t ideal_height = text_height + ws_vertical_padding * 2; |
47 | uint32_t ideal_surface_height = ideal_height / output->scale; | 71 | uint32_t ideal_surface_height = ideal_height; |
48 | if (!output->bar->config->height && | 72 | if (!output->bar->config->height && |
49 | output->height < ideal_surface_height) { | 73 | output->height < ideal_surface_height) { |
50 | return ideal_surface_height; | 74 | return ideal_surface_height; |
@@ -53,42 +77,45 @@ static uint32_t render_status_line_error(cairo_t *cairo, | |||
53 | 77 | ||
54 | double text_y = height / 2.0 - text_height / 2.0; | 78 | double text_y = height / 2.0 - text_height / 2.0; |
55 | cairo_move_to(cairo, *x, (int)floor(text_y)); | 79 | cairo_move_to(cairo, *x, (int)floor(text_y)); |
56 | pango_printf(cairo, font, output->scale, false, "%s", error); | 80 | choose_text_aa_mode(ctx, 0xFF0000FF); |
81 | render_text(cairo, font, 1, false, "%s", error); | ||
57 | *x -= margin; | 82 | *x -= margin; |
58 | return output->height; | 83 | return output->height; |
59 | } | 84 | } |
60 | 85 | ||
61 | static uint32_t render_status_line_text(cairo_t *cairo, | 86 | static uint32_t render_status_line_text(struct render_context *ctx, double *x) { |
62 | struct swaybar_output *output, double *x) { | 87 | struct swaybar_output *output = ctx->output; |
63 | const char *text = output->bar->status->text; | 88 | const char *text = output->bar->status->text; |
64 | if (!text) { | 89 | if (!text) { |
65 | return 0; | 90 | return 0; |
66 | } | 91 | } |
67 | 92 | ||
93 | cairo_t *cairo = ctx->cairo; | ||
68 | struct swaybar_config *config = output->bar->config; | 94 | struct swaybar_config *config = output->bar->config; |
69 | cairo_set_source_u32(cairo, output->focused ? | 95 | uint32_t fontcolor = output->focused ? |
70 | config->colors.focused_statusline : config->colors.statusline); | 96 | config->colors.focused_statusline : config->colors.statusline; |
97 | cairo_set_source_u32(cairo, fontcolor); | ||
71 | 98 | ||
72 | int text_width, text_height; | 99 | int text_width, text_height; |
73 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, | 100 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, |
74 | output->scale, config->pango_markup, "%s", text); | 101 | 1, config->pango_markup, "%s", text); |
75 | 102 | ||
76 | double ws_vertical_padding = config->status_padding * output->scale; | 103 | double ws_vertical_padding = config->status_padding; |
77 | int margin = 3 * output->scale; | 104 | int margin = 3; |
78 | 105 | ||
79 | uint32_t ideal_height = text_height + ws_vertical_padding * 2; | 106 | uint32_t ideal_height = text_height + ws_vertical_padding * 2; |
80 | uint32_t ideal_surface_height = ideal_height / output->scale; | 107 | uint32_t ideal_surface_height = ideal_height; |
81 | if (!output->bar->config->height && | 108 | if (!output->bar->config->height && |
82 | output->height < ideal_surface_height) { | 109 | output->height < ideal_surface_height) { |
83 | return ideal_surface_height; | 110 | return ideal_surface_height; |
84 | } | 111 | } |
85 | 112 | ||
86 | *x -= text_width + margin; | 113 | *x -= text_width + margin; |
87 | uint32_t height = output->height * output->scale; | 114 | uint32_t height = output->height; |
88 | double text_y = height / 2.0 - text_height / 2.0; | 115 | double text_y = height / 2.0 - text_height / 2.0; |
89 | cairo_move_to(cairo, *x, (int)floor(text_y)); | 116 | cairo_move_to(cairo, *x, (int)floor(text_y)); |
90 | pango_printf(cairo, config->font, output->scale, | 117 | choose_text_aa_mode(ctx, fontcolor); |
91 | config->pango_markup, "%s", text); | 118 | render_text(cairo, config->font, 1, config->pango_markup, "%s", text); |
92 | *x -= margin; | 119 | *x -= margin; |
93 | return output->height; | 120 | return output->height; |
94 | } | 121 | } |
@@ -96,6 +123,7 @@ static uint32_t render_status_line_text(cairo_t *cairo, | |||
96 | static void render_sharp_rectangle(cairo_t *cairo, uint32_t color, | 123 | static void render_sharp_rectangle(cairo_t *cairo, uint32_t color, |
97 | double x, double y, double width, double height) { | 124 | double x, double y, double width, double height) { |
98 | cairo_save(cairo); | 125 | cairo_save(cairo); |
126 | cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); | ||
99 | cairo_set_source_u32(cairo, color); | 127 | cairo_set_source_u32(cairo, color); |
100 | cairo_set_antialias(cairo, CAIRO_ANTIALIAS_NONE); | 128 | cairo_set_antialias(cairo, CAIRO_ANTIALIAS_NONE); |
101 | cairo_rectangle(cairo, x, y, width, height); | 129 | cairo_rectangle(cairo, x, y, width, height); |
@@ -109,6 +137,7 @@ static void render_sharp_line(cairo_t *cairo, uint32_t color, | |||
109 | render_sharp_rectangle(cairo, color, x, y, width, height); | 137 | render_sharp_rectangle(cairo, color, x, y, width, height); |
110 | } else { | 138 | } else { |
111 | cairo_save(cairo); | 139 | cairo_save(cairo); |
140 | cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); | ||
112 | cairo_set_source_u32(cairo, color); | 141 | cairo_set_source_u32(cairo, color); |
113 | cairo_set_antialias(cairo, CAIRO_ANTIALIAS_NONE); | 142 | cairo_set_antialias(cairo, CAIRO_ANTIALIAS_NONE); |
114 | if (width == 1) { | 143 | if (width == 1) { |
@@ -135,10 +164,10 @@ static enum hotspot_event_handling block_hotspot_callback( | |||
135 | struct i3bar_block *block = data; | 164 | struct i3bar_block *block = data; |
136 | struct status_line *status = output->bar->status; | 165 | struct status_line *status = output->bar->status; |
137 | return i3bar_block_send_click(status, block, x, y, | 166 | return i3bar_block_send_click(status, block, x, y, |
138 | x - (double)hotspot->x / output->scale, | 167 | x - (double)hotspot->x, |
139 | y - (double)hotspot->y / output->scale, | 168 | y - (double)hotspot->y, |
140 | (double)hotspot->width / output->scale, | 169 | (double)hotspot->width, |
141 | (double)hotspot->height / output->scale, | 170 | (double)hotspot->height, |
142 | output->scale, button); | 171 | output->scale, button); |
143 | } | 172 | } |
144 | 173 | ||
@@ -146,9 +175,8 @@ static void i3bar_block_unref_callback(void *data) { | |||
146 | i3bar_block_unref(data); | 175 | i3bar_block_unref(data); |
147 | } | 176 | } |
148 | 177 | ||
149 | static uint32_t render_status_block(cairo_t *cairo, | 178 | static uint32_t render_status_block(struct render_context *ctx, |
150 | struct swaybar_output *output, struct i3bar_block *block, double *x, | 179 | struct i3bar_block *block, double *x, bool edge, bool use_short_text) { |
151 | bool edge, bool use_short_text) { | ||
152 | if (!block->full_text || !*block->full_text) { | 180 | if (!block->full_text || !*block->full_text) { |
153 | return 0; | 181 | return 0; |
154 | } | 182 | } |
@@ -158,20 +186,21 @@ static uint32_t render_status_block(cairo_t *cairo, | |||
158 | text = block->short_text; | 186 | text = block->short_text; |
159 | } | 187 | } |
160 | 188 | ||
189 | cairo_t *cairo = ctx->cairo; | ||
190 | struct swaybar_output *output = ctx->output; | ||
161 | struct swaybar_config *config = output->bar->config; | 191 | struct swaybar_config *config = output->bar->config; |
162 | |||
163 | int text_width, text_height; | 192 | int text_width, text_height; |
164 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, | 193 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, 1, |
165 | output->scale, block->markup, "%s", text); | 194 | block->markup, "%s", text); |
166 | 195 | ||
167 | int margin = 3 * output->scale; | 196 | int margin = 3; |
168 | double ws_vertical_padding = config->status_padding * output->scale; | 197 | double ws_vertical_padding = config->status_padding; |
169 | 198 | ||
170 | int width = text_width; | 199 | int width = text_width; |
171 | if (block->min_width_str) { | 200 | if (block->min_width_str) { |
172 | int w; | 201 | int w; |
173 | get_text_size(cairo, config->font, &w, NULL, NULL, | 202 | get_text_size(cairo, config->font, &w, NULL, NULL, 1, block->markup, |
174 | output->scale, block->markup, "%s", block->min_width_str); | 203 | "%s", block->min_width_str); |
175 | block->min_width = w; | 204 | block->min_width = w; |
176 | } | 205 | } |
177 | if (width < block->min_width) { | 206 | if (width < block->min_width) { |
@@ -180,20 +209,20 @@ static uint32_t render_status_block(cairo_t *cairo, | |||
180 | 209 | ||
181 | double block_width = width; | 210 | double block_width = width; |
182 | uint32_t ideal_height = text_height + ws_vertical_padding * 2; | 211 | uint32_t ideal_height = text_height + ws_vertical_padding * 2; |
183 | uint32_t ideal_surface_height = ideal_height / output->scale; | 212 | uint32_t ideal_surface_height = ideal_height; |
184 | if (!output->bar->config->height && | 213 | if (!output->bar->config->height && |
185 | output->height < ideal_surface_height) { | 214 | output->height < ideal_surface_height) { |
186 | return ideal_surface_height; | 215 | return ideal_surface_height; |
187 | } | 216 | } |
188 | 217 | ||
189 | *x -= width; | 218 | *x -= width; |
190 | if ((block->border || block->urgent) && block->border_left > 0) { | 219 | if ((block->border_set || block->urgent) && block->border_left > 0) { |
191 | *x -= (block->border_left * output->scale + margin); | 220 | *x -= (block->border_left + margin); |
192 | block_width += block->border_left * output->scale + margin; | 221 | block_width += block->border_left + margin; |
193 | } | 222 | } |
194 | if ((block->border || block->urgent) && block->border_right > 0) { | 223 | if ((block->border_set || block->urgent) && block->border_right > 0) { |
195 | *x -= (block->border_right * output->scale + margin); | 224 | *x -= (block->border_right + margin); |
196 | block_width += block->border_right * output->scale + margin; | 225 | block_width += block->border_right + margin; |
197 | } | 226 | } |
198 | 227 | ||
199 | int sep_width, sep_height; | 228 | int sep_width, sep_height; |
@@ -201,9 +230,9 @@ static uint32_t render_status_block(cairo_t *cairo, | |||
201 | if (!edge) { | 230 | if (!edge) { |
202 | if (config->sep_symbol) { | 231 | if (config->sep_symbol) { |
203 | get_text_size(cairo, config->font, &sep_width, &sep_height, NULL, | 232 | get_text_size(cairo, config->font, &sep_width, &sep_height, NULL, |
204 | output->scale, false, "%s", config->sep_symbol); | 233 | 1, false, "%s", config->sep_symbol); |
205 | uint32_t _ideal_height = sep_height + ws_vertical_padding * 2; | 234 | uint32_t _ideal_height = sep_height + ws_vertical_padding * 2; |
206 | uint32_t _ideal_surface_height = _ideal_height / output->scale; | 235 | uint32_t _ideal_surface_height = _ideal_height; |
207 | if (!output->bar->config->height && | 236 | if (!output->bar->config->height && |
208 | output->height < _ideal_surface_height) { | 237 | output->height < _ideal_surface_height) { |
209 | return _ideal_surface_height; | 238 | return _ideal_surface_height; |
@@ -214,10 +243,10 @@ static uint32_t render_status_block(cairo_t *cairo, | |||
214 | } | 243 | } |
215 | *x -= sep_block_width; | 244 | *x -= sep_block_width; |
216 | } else if (config->status_edge_padding) { | 245 | } else if (config->status_edge_padding) { |
217 | *x -= config->status_edge_padding * output->scale; | 246 | *x -= config->status_edge_padding; |
218 | } | 247 | } |
219 | 248 | ||
220 | uint32_t height = output->height * output->scale; | 249 | uint32_t height = output->height; |
221 | if (output->bar->status->click_events) { | 250 | if (output->bar->status->click_events) { |
222 | struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); | 251 | struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); |
223 | hotspot->x = *x; | 252 | hotspot->x = *x; |
@@ -240,23 +269,26 @@ static uint32_t render_status_block(cairo_t *cairo, | |||
240 | if (bg_color) { | 269 | if (bg_color) { |
241 | render_sharp_rectangle(cairo, bg_color, x_pos, y_pos, | 270 | render_sharp_rectangle(cairo, bg_color, x_pos, y_pos, |
242 | block_width, render_height); | 271 | block_width, render_height); |
272 | ctx->background_color = bg_color; | ||
243 | } | 273 | } |
244 | 274 | ||
245 | uint32_t border_color = block->urgent | 275 | uint32_t border_color = block->urgent |
246 | ? config->colors.urgent_workspace.border : block->border; | 276 | ? config->colors.urgent_workspace.border : block->border; |
247 | if (border_color && block->border_top > 0) { | 277 | if (block->border_set || block->urgent) { |
248 | render_sharp_line(cairo, border_color, x_pos, y_pos, | 278 | if (block->border_top > 0) { |
249 | block_width, block->border_top * output->scale); | 279 | render_sharp_line(cairo, border_color, x_pos, y_pos, |
250 | } | 280 | block_width, block->border_top); |
251 | if (border_color && block->border_bottom > 0) { | 281 | } |
252 | render_sharp_line(cairo, border_color, x_pos, | 282 | if (block->border_bottom > 0) { |
253 | y_pos + render_height - block->border_bottom * output->scale, | 283 | render_sharp_line(cairo, border_color, x_pos, |
254 | block_width, block->border_bottom * output->scale); | 284 | y_pos + render_height - block->border_bottom, |
255 | } | 285 | block_width, block->border_bottom); |
256 | if (border_color && block->border_left > 0) { | 286 | } |
257 | render_sharp_line(cairo, border_color, x_pos, y_pos, | 287 | if (block->border_left > 0) { |
258 | block->border_left * output->scale, render_height); | 288 | render_sharp_line(cairo, border_color, x_pos, y_pos, |
259 | x_pos += block->border_left * output->scale + margin; | 289 | block->border_left, render_height); |
290 | } | ||
291 | x_pos += block->border_left + margin; | ||
260 | } | 292 | } |
261 | 293 | ||
262 | double offset = 0; | 294 | double offset = 0; |
@@ -274,30 +306,35 @@ static uint32_t render_status_block(cairo_t *cairo, | |||
274 | color = block->color_set ? block->color : color; | 306 | color = block->color_set ? block->color : color; |
275 | color = block->urgent ? config->colors.urgent_workspace.text : color; | 307 | color = block->urgent ? config->colors.urgent_workspace.text : color; |
276 | cairo_set_source_u32(cairo, color); | 308 | cairo_set_source_u32(cairo, color); |
277 | pango_printf(cairo, config->font, output->scale, | 309 | choose_text_aa_mode(ctx, color); |
278 | block->markup, "%s", text); | 310 | render_text(cairo, config->font, 1, block->markup, "%s", text); |
279 | x_pos += width; | 311 | x_pos += width; |
280 | 312 | ||
281 | if (block->border && block->border_right > 0) { | 313 | if (block->border_set || block->urgent) { |
282 | x_pos += margin; | 314 | x_pos += margin; |
283 | render_sharp_line(cairo, border_color, x_pos, y_pos, | 315 | if (block->border_right > 0) { |
284 | block->border_right * output->scale, render_height); | 316 | render_sharp_line(cairo, border_color, x_pos, y_pos, |
285 | x_pos += block->border_right * output->scale; | 317 | block->border_right, render_height); |
318 | } | ||
319 | x_pos += block->border_right; | ||
286 | } | 320 | } |
287 | 321 | ||
288 | if (!edge && block->separator) { | 322 | if (!edge && block->separator) { |
289 | if (output->focused) { | 323 | if (output->focused) { |
290 | cairo_set_source_u32(cairo, config->colors.focused_separator); | 324 | color = config->colors.focused_separator; |
291 | } else { | 325 | } else { |
292 | cairo_set_source_u32(cairo, config->colors.separator); | 326 | color = config->colors.separator; |
293 | } | 327 | } |
328 | cairo_set_source_u32(cairo, color); | ||
294 | if (config->sep_symbol) { | 329 | if (config->sep_symbol) { |
295 | offset = x_pos + (sep_block_width - sep_width) / 2; | 330 | offset = x_pos + (sep_block_width - sep_width) / 2; |
296 | double sep_y = height / 2.0 - sep_height / 2.0; | 331 | double sep_y = height / 2.0 - sep_height / 2.0; |
297 | cairo_move_to(cairo, offset, (int)floor(sep_y)); | 332 | cairo_move_to(cairo, offset, (int)floor(sep_y)); |
298 | pango_printf(cairo, config->font, output->scale, false, | 333 | choose_text_aa_mode(ctx, color); |
334 | render_text(cairo, config->font, 1, false, | ||
299 | "%s", config->sep_symbol); | 335 | "%s", config->sep_symbol); |
300 | } else { | 336 | } else { |
337 | cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); | ||
301 | cairo_set_line_width(cairo, 1); | 338 | cairo_set_line_width(cairo, 1); |
302 | cairo_move_to(cairo, x_pos + sep_block_width / 2, margin); | 339 | cairo_move_to(cairo, x_pos + sep_block_width / 2, margin); |
303 | cairo_line_to(cairo, x_pos + sep_block_width / 2, height - margin); | 340 | cairo_line_to(cairo, x_pos + sep_block_width / 2, height - margin); |
@@ -317,18 +354,18 @@ static void predict_status_block_pos(cairo_t *cairo, | |||
317 | struct swaybar_config *config = output->bar->config; | 354 | struct swaybar_config *config = output->bar->config; |
318 | 355 | ||
319 | int text_width, text_height; | 356 | int text_width, text_height; |
320 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, | 357 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, 1, |
321 | output->scale, block->markup, "%s", block->full_text); | 358 | block->markup, "%s", block->full_text); |
322 | 359 | ||
323 | int margin = 3 * output->scale; | 360 | int margin = 3; |
324 | double ws_vertical_padding = config->status_padding * output->scale; | 361 | double ws_vertical_padding = config->status_padding; |
325 | 362 | ||
326 | int width = text_width; | 363 | int width = text_width; |
327 | 364 | ||
328 | if (block->min_width_str) { | 365 | if (block->min_width_str) { |
329 | int w; | 366 | int w; |
330 | get_text_size(cairo, config->font, &w, NULL, NULL, | 367 | get_text_size(cairo, config->font, &w, NULL, NULL, |
331 | output->scale, block->markup, "%s", block->min_width_str); | 368 | 1, block->markup, "%s", block->min_width_str); |
332 | block->min_width = w; | 369 | block->min_width = w; |
333 | } | 370 | } |
334 | if (width < block->min_width) { | 371 | if (width < block->min_width) { |
@@ -336,18 +373,18 @@ static void predict_status_block_pos(cairo_t *cairo, | |||
336 | } | 373 | } |
337 | 374 | ||
338 | uint32_t ideal_height = text_height + ws_vertical_padding * 2; | 375 | uint32_t ideal_height = text_height + ws_vertical_padding * 2; |
339 | uint32_t ideal_surface_height = ideal_height / output->scale; | 376 | uint32_t ideal_surface_height = ideal_height; |
340 | if (!output->bar->config->height && | 377 | if (!output->bar->config->height && |
341 | output->height < ideal_surface_height) { | 378 | output->height < ideal_surface_height) { |
342 | return; | 379 | return; |
343 | } | 380 | } |
344 | 381 | ||
345 | *x -= width; | 382 | *x -= width; |
346 | if ((block->border || block->urgent) && block->border_left > 0) { | 383 | if ((block->border_set || block->urgent) && block->border_left > 0) { |
347 | *x -= (block->border_left * output->scale + margin); | 384 | *x -= (block->border_left + margin); |
348 | } | 385 | } |
349 | if ((block->border || block->urgent) && block->border_right > 0) { | 386 | if ((block->border_set || block->urgent) && block->border_right > 0) { |
350 | *x -= (block->border_right * output->scale + margin); | 387 | *x -= (block->border_right + margin); |
351 | } | 388 | } |
352 | 389 | ||
353 | int sep_width, sep_height; | 390 | int sep_width, sep_height; |
@@ -355,9 +392,9 @@ static void predict_status_block_pos(cairo_t *cairo, | |||
355 | if (!edge) { | 392 | if (!edge) { |
356 | if (config->sep_symbol) { | 393 | if (config->sep_symbol) { |
357 | get_text_size(cairo, config->font, &sep_width, &sep_height, NULL, | 394 | get_text_size(cairo, config->font, &sep_width, &sep_height, NULL, |
358 | output->scale, false, "%s", config->sep_symbol); | 395 | 1, false, "%s", config->sep_symbol); |
359 | uint32_t _ideal_height = sep_height + ws_vertical_padding * 2; | 396 | uint32_t _ideal_height = sep_height + ws_vertical_padding * 2; |
360 | uint32_t _ideal_surface_height = _ideal_height / output->scale; | 397 | uint32_t _ideal_surface_height = _ideal_height; |
361 | if (!output->bar->config->height && | 398 | if (!output->bar->config->height && |
362 | output->height < _ideal_surface_height) { | 399 | output->height < _ideal_surface_height) { |
363 | return; | 400 | return; |
@@ -368,13 +405,13 @@ static void predict_status_block_pos(cairo_t *cairo, | |||
368 | } | 405 | } |
369 | *x -= sep_block_width; | 406 | *x -= sep_block_width; |
370 | } else if (config->status_edge_padding) { | 407 | } else if (config->status_edge_padding) { |
371 | *x -= config->status_edge_padding * output->scale; | 408 | *x -= config->status_edge_padding; |
372 | } | 409 | } |
373 | } | 410 | } |
374 | 411 | ||
375 | static double predict_status_line_pos(cairo_t *cairo, | 412 | static double predict_status_line_pos(cairo_t *cairo, |
376 | struct swaybar_output *output, double x) { | 413 | struct swaybar_output *output, double x) { |
377 | bool edge = x == output->width * output->scale; | 414 | bool edge = x == output->width; |
378 | struct i3bar_block *block; | 415 | struct i3bar_block *block; |
379 | wl_list_for_each(block, &output->bar->status->blocks, link) { | 416 | wl_list_for_each(block, &output->bar->status->blocks, link) { |
380 | predict_status_block_pos(cairo, output, block, &x, edge); | 417 | predict_status_block_pos(cairo, output, block, &x, edge); |
@@ -389,24 +426,24 @@ static uint32_t predict_workspace_button_length(cairo_t *cairo, | |||
389 | struct swaybar_config *config = output->bar->config; | 426 | struct swaybar_config *config = output->bar->config; |
390 | 427 | ||
391 | int text_width, text_height; | 428 | int text_width, text_height; |
392 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, | 429 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, 1, |
393 | output->scale, config->pango_markup, "%s", ws->label); | 430 | config->pango_markup, "%s", ws->label); |
394 | 431 | ||
395 | int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; | 432 | int ws_vertical_padding = WS_VERTICAL_PADDING; |
396 | int ws_horizontal_padding = WS_HORIZONTAL_PADDING * output->scale; | 433 | int ws_horizontal_padding = WS_HORIZONTAL_PADDING; |
397 | int border_width = BORDER_WIDTH * output->scale; | 434 | int border_width = BORDER_WIDTH; |
398 | 435 | ||
399 | uint32_t ideal_height = ws_vertical_padding * 2 + text_height | 436 | uint32_t ideal_height = ws_vertical_padding * 2 + text_height |
400 | + border_width * 2; | 437 | + border_width * 2; |
401 | uint32_t ideal_surface_height = ideal_height / output->scale; | 438 | uint32_t ideal_surface_height = ideal_height; |
402 | if (!output->bar->config->height && | 439 | if (!output->bar->config->height && |
403 | output->height < ideal_surface_height) { | 440 | output->height < ideal_surface_height) { |
404 | return 0; | 441 | return 0; |
405 | } | 442 | } |
406 | 443 | ||
407 | uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; | 444 | uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; |
408 | if (width < config->workspace_min_width * output->scale) { | 445 | if (width < config->workspace_min_width) { |
409 | width = config->workspace_min_width * output->scale; | 446 | width = config->workspace_min_width; |
410 | } | 447 | } |
411 | return width; | 448 | return width; |
412 | } | 449 | } |
@@ -438,38 +475,39 @@ static uint32_t predict_binding_mode_indicator_length(cairo_t *cairo, | |||
438 | 475 | ||
439 | int text_width, text_height; | 476 | int text_width, text_height; |
440 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, | 477 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, |
441 | output->scale, output->bar->mode_pango_markup, | 478 | 1, output->bar->mode_pango_markup, |
442 | "%s", mode); | 479 | "%s", mode); |
443 | 480 | ||
444 | int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; | 481 | int ws_vertical_padding = WS_VERTICAL_PADDING; |
445 | int ws_horizontal_padding = WS_HORIZONTAL_PADDING * output->scale; | 482 | int ws_horizontal_padding = WS_HORIZONTAL_PADDING; |
446 | int border_width = BORDER_WIDTH * output->scale; | 483 | int border_width = BORDER_WIDTH; |
447 | 484 | ||
448 | uint32_t ideal_height = text_height + ws_vertical_padding * 2 | 485 | uint32_t ideal_height = text_height + ws_vertical_padding * 2 |
449 | + border_width * 2; | 486 | + border_width * 2; |
450 | uint32_t ideal_surface_height = ideal_height / output->scale; | 487 | uint32_t ideal_surface_height = ideal_height; |
451 | if (!output->bar->config->height && | 488 | if (!output->bar->config->height && |
452 | output->height < ideal_surface_height) { | 489 | output->height < ideal_surface_height) { |
453 | return 0; | 490 | return 0; |
454 | } | 491 | } |
455 | uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; | 492 | uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; |
456 | if (width < config->workspace_min_width * output->scale) { | 493 | if (width < config->workspace_min_width) { |
457 | width = config->workspace_min_width * output->scale; | 494 | width = config->workspace_min_width; |
458 | } | 495 | } |
459 | return width; | 496 | return width; |
460 | } | 497 | } |
461 | 498 | ||
462 | static uint32_t render_status_line_i3bar(cairo_t *cairo, | 499 | static uint32_t render_status_line_i3bar(struct render_context *ctx, double *x) { |
463 | struct swaybar_output *output, double *x) { | 500 | struct swaybar_output *output = ctx->output; |
464 | uint32_t max_height = 0; | 501 | uint32_t max_height = 0; |
465 | bool edge = *x == output->width * output->scale; | 502 | bool edge = *x == output->width; |
466 | struct i3bar_block *block; | 503 | struct i3bar_block *block; |
467 | bool use_short_text = false; | 504 | bool use_short_text = false; |
468 | 505 | ||
506 | cairo_t *cairo = ctx->cairo; | ||
469 | double reserved_width = | 507 | double reserved_width = |
470 | predict_workspace_buttons_length(cairo, output) + | 508 | predict_workspace_buttons_length(cairo, output) + |
471 | predict_binding_mode_indicator_length(cairo, output) + | 509 | predict_binding_mode_indicator_length(cairo, output) + |
472 | 3 * output->scale; // require a bit of space for margin | 510 | 3; // require a bit of space for margin |
473 | 511 | ||
474 | double predicted_full_pos = | 512 | double predicted_full_pos = |
475 | predict_status_line_pos(cairo, output, *x); | 513 | predict_status_line_pos(cairo, output, *x); |
@@ -479,7 +517,7 @@ static uint32_t render_status_line_i3bar(cairo_t *cairo, | |||
479 | } | 517 | } |
480 | 518 | ||
481 | wl_list_for_each(block, &output->bar->status->blocks, link) { | 519 | wl_list_for_each(block, &output->bar->status->blocks, link) { |
482 | uint32_t h = render_status_block(cairo, output, block, x, edge, | 520 | uint32_t h = render_status_block(ctx, block, x, edge, |
483 | use_short_text); | 521 | use_short_text); |
484 | max_height = h > max_height ? h : max_height; | 522 | max_height = h > max_height ? h : max_height; |
485 | edge = false; | 523 | edge = false; |
@@ -487,53 +525,56 @@ static uint32_t render_status_line_i3bar(cairo_t *cairo, | |||
487 | return max_height; | 525 | return max_height; |
488 | } | 526 | } |
489 | 527 | ||
490 | static uint32_t render_status_line(cairo_t *cairo, | 528 | static uint32_t render_status_line(struct render_context *ctx, double *x) { |
491 | struct swaybar_output *output, double *x) { | 529 | struct status_line *status = ctx->output->bar->status; |
492 | struct status_line *status = output->bar->status; | ||
493 | switch (status->protocol) { | 530 | switch (status->protocol) { |
494 | case PROTOCOL_ERROR: | 531 | case PROTOCOL_ERROR: |
495 | return render_status_line_error(cairo, output, x); | 532 | return render_status_line_error(ctx, x); |
496 | case PROTOCOL_TEXT: | 533 | case PROTOCOL_TEXT: |
497 | return render_status_line_text(cairo, output, x); | 534 | return render_status_line_text(ctx, x); |
498 | case PROTOCOL_I3BAR: | 535 | case PROTOCOL_I3BAR: |
499 | return render_status_line_i3bar(cairo, output, x); | 536 | return render_status_line_i3bar(ctx, x); |
500 | case PROTOCOL_UNDEF: | 537 | case PROTOCOL_UNDEF: |
501 | return 0; | 538 | return 0; |
502 | } | 539 | } |
503 | return 0; | 540 | return 0; |
504 | } | 541 | } |
505 | 542 | ||
506 | static uint32_t render_binding_mode_indicator(cairo_t *cairo, | 543 | static uint32_t render_binding_mode_indicator(struct render_context *ctx, |
507 | struct swaybar_output *output, double x) { | 544 | double x) { |
545 | struct swaybar_output *output = ctx->output; | ||
508 | const char *mode = output->bar->mode; | 546 | const char *mode = output->bar->mode; |
509 | if (!mode) { | 547 | if (!mode) { |
510 | return 0; | 548 | return 0; |
511 | } | 549 | } |
512 | 550 | ||
551 | cairo_t *cairo = ctx->cairo; | ||
513 | struct swaybar_config *config = output->bar->config; | 552 | struct swaybar_config *config = output->bar->config; |
514 | int text_width, text_height; | 553 | int text_width, text_height; |
515 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, | 554 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, |
516 | output->scale, output->bar->mode_pango_markup, | 555 | 1, output->bar->mode_pango_markup, |
517 | "%s", mode); | 556 | "%s", mode); |
518 | 557 | ||
519 | int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; | 558 | int ws_vertical_padding = WS_VERTICAL_PADDING; |
520 | int ws_horizontal_padding = WS_HORIZONTAL_PADDING * output->scale; | 559 | int ws_horizontal_padding = WS_HORIZONTAL_PADDING; |
521 | int border_width = BORDER_WIDTH * output->scale; | 560 | int border_width = BORDER_WIDTH; |
522 | 561 | ||
523 | uint32_t ideal_height = text_height + ws_vertical_padding * 2 | 562 | uint32_t ideal_height = text_height + ws_vertical_padding * 2 |
524 | + border_width * 2; | 563 | + border_width * 2; |
525 | uint32_t ideal_surface_height = ideal_height / output->scale; | 564 | uint32_t ideal_surface_height = ideal_height; |
526 | if (!output->bar->config->height && | 565 | if (!output->bar->config->height && |
527 | output->height < ideal_surface_height) { | 566 | output->height < ideal_surface_height) { |
528 | return ideal_surface_height; | 567 | return ideal_surface_height; |
529 | } | 568 | } |
530 | uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; | 569 | uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; |
531 | if (width < config->workspace_min_width * output->scale) { | 570 | if (width < config->workspace_min_width) { |
532 | width = config->workspace_min_width * output->scale; | 571 | width = config->workspace_min_width; |
533 | } | 572 | } |
534 | 573 | ||
535 | uint32_t height = output->height * output->scale; | 574 | uint32_t height = output->height; |
575 | cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); | ||
536 | cairo_set_source_u32(cairo, config->colors.binding_mode.background); | 576 | cairo_set_source_u32(cairo, config->colors.binding_mode.background); |
577 | ctx->background_color = config->colors.binding_mode.background; | ||
537 | cairo_rectangle(cairo, x, 0, width, height); | 578 | cairo_rectangle(cairo, x, 0, width, height); |
538 | cairo_fill(cairo); | 579 | cairo_fill(cairo); |
539 | 580 | ||
@@ -550,8 +591,9 @@ static uint32_t render_binding_mode_indicator(cairo_t *cairo, | |||
550 | double text_y = height / 2.0 - text_height / 2.0; | 591 | double text_y = height / 2.0 - text_height / 2.0; |
551 | cairo_set_source_u32(cairo, config->colors.binding_mode.text); | 592 | cairo_set_source_u32(cairo, config->colors.binding_mode.text); |
552 | cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y)); | 593 | cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y)); |
553 | pango_printf(cairo, config->font, output->scale, | 594 | choose_text_aa_mode(ctx, config->colors.binding_mode.text); |
554 | output->bar->mode_pango_markup, "%s", mode); | 595 | render_text(cairo, config->font, 1, output->bar->mode_pango_markup, |
596 | "%s", mode); | ||
555 | return output->height; | 597 | return output->height; |
556 | } | 598 | } |
557 | 599 | ||
@@ -565,9 +607,9 @@ static enum hotspot_event_handling workspace_hotspot_callback( | |||
565 | return HOTSPOT_IGNORE; | 607 | return HOTSPOT_IGNORE; |
566 | } | 608 | } |
567 | 609 | ||
568 | static uint32_t render_workspace_button(cairo_t *cairo, | 610 | static uint32_t render_workspace_button(struct render_context *ctx, |
569 | struct swaybar_output *output, | ||
570 | struct swaybar_workspace *ws, double *x) { | 611 | struct swaybar_workspace *ws, double *x) { |
612 | struct swaybar_output *output = ctx->output; | ||
571 | struct swaybar_config *config = output->bar->config; | 613 | struct swaybar_config *config = output->bar->config; |
572 | struct box_colors box_colors; | 614 | struct box_colors box_colors; |
573 | if (ws->urgent) { | 615 | if (ws->urgent) { |
@@ -580,30 +622,33 @@ static uint32_t render_workspace_button(cairo_t *cairo, | |||
580 | box_colors = config->colors.inactive_workspace; | 622 | box_colors = config->colors.inactive_workspace; |
581 | } | 623 | } |
582 | 624 | ||
583 | uint32_t height = output->height * output->scale; | 625 | uint32_t height = output->height; |
584 | 626 | ||
627 | cairo_t *cairo = ctx->cairo; | ||
585 | int text_width, text_height; | 628 | int text_width, text_height; |
586 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, | 629 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, |
587 | output->scale, config->pango_markup, "%s", ws->label); | 630 | 1, config->pango_markup, "%s", ws->label); |
588 | 631 | ||
589 | int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; | 632 | int ws_vertical_padding = WS_VERTICAL_PADDING; |
590 | int ws_horizontal_padding = WS_HORIZONTAL_PADDING * output->scale; | 633 | int ws_horizontal_padding = WS_HORIZONTAL_PADDING; |
591 | int border_width = BORDER_WIDTH * output->scale; | 634 | int border_width = BORDER_WIDTH; |
592 | 635 | ||
593 | uint32_t ideal_height = ws_vertical_padding * 2 + text_height | 636 | uint32_t ideal_height = ws_vertical_padding * 2 + text_height |
594 | + border_width * 2; | 637 | + border_width * 2; |
595 | uint32_t ideal_surface_height = ideal_height / output->scale; | 638 | uint32_t ideal_surface_height = ideal_height; |
596 | if (!output->bar->config->height && | 639 | if (!output->bar->config->height && |
597 | output->height < ideal_surface_height) { | 640 | output->height < ideal_surface_height) { |
598 | return ideal_surface_height; | 641 | return ideal_surface_height; |
599 | } | 642 | } |
600 | 643 | ||
601 | uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; | 644 | uint32_t width = text_width + ws_horizontal_padding * 2 + border_width * 2; |
602 | if (width < config->workspace_min_width * output->scale) { | 645 | if (width < config->workspace_min_width) { |
603 | width = config->workspace_min_width * output->scale; | 646 | width = config->workspace_min_width; |
604 | } | 647 | } |
605 | 648 | ||
649 | cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); | ||
606 | cairo_set_source_u32(cairo, box_colors.background); | 650 | cairo_set_source_u32(cairo, box_colors.background); |
651 | ctx->background_color = box_colors.background; | ||
607 | cairo_rectangle(cairo, *x, 0, width, height); | 652 | cairo_rectangle(cairo, *x, 0, width, height); |
608 | cairo_fill(cairo); | 653 | cairo_fill(cairo); |
609 | 654 | ||
@@ -620,7 +665,8 @@ static uint32_t render_workspace_button(cairo_t *cairo, | |||
620 | double text_y = height / 2.0 - text_height / 2.0; | 665 | double text_y = height / 2.0 - text_height / 2.0; |
621 | cairo_set_source_u32(cairo, box_colors.text); | 666 | cairo_set_source_u32(cairo, box_colors.text); |
622 | cairo_move_to(cairo, *x + width / 2 - text_width / 2, (int)floor(text_y)); | 667 | cairo_move_to(cairo, *x + width / 2 - text_width / 2, (int)floor(text_y)); |
623 | pango_printf(cairo, config->font, output->scale, config->pango_markup, | 668 | choose_text_aa_mode(ctx, box_colors.text); |
669 | render_text(cairo, config->font, 1, config->pango_markup, | ||
624 | "%s", ws->label); | 670 | "%s", ws->label); |
625 | 671 | ||
626 | struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); | 672 | struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); |
@@ -637,20 +683,24 @@ static uint32_t render_workspace_button(cairo_t *cairo, | |||
637 | return output->height; | 683 | return output->height; |
638 | } | 684 | } |
639 | 685 | ||
640 | static uint32_t render_to_cairo(cairo_t *cairo, struct swaybar_output *output) { | 686 | static uint32_t render_to_cairo(struct render_context *ctx) { |
687 | cairo_t *cairo = ctx->cairo; | ||
688 | struct swaybar_output *output = ctx->output; | ||
641 | struct swaybar *bar = output->bar; | 689 | struct swaybar *bar = output->bar; |
642 | struct swaybar_config *config = bar->config; | 690 | struct swaybar_config *config = bar->config; |
643 | cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); | 691 | cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE); |
644 | if (output->focused) { | 692 | if (output->focused) { |
645 | cairo_set_source_u32(cairo, config->colors.focused_background); | 693 | ctx->background_color = config->colors.focused_background; |
646 | } else { | 694 | } else { |
647 | cairo_set_source_u32(cairo, config->colors.background); | 695 | ctx->background_color = config->colors.background; |
648 | } | 696 | } |
697 | |||
698 | cairo_set_source_u32(cairo, ctx->background_color); | ||
649 | cairo_paint(cairo); | 699 | cairo_paint(cairo); |
650 | 700 | ||
651 | int th; | 701 | int th; |
652 | get_text_size(cairo, config->font, NULL, &th, NULL, output->scale, false, ""); | 702 | get_text_size(cairo, config->font, NULL, &th, NULL, 1, false, ""); |
653 | uint32_t max_height = (th + WS_VERTICAL_PADDING * 4) / output->scale; | 703 | uint32_t max_height = (th + WS_VERTICAL_PADDING * 4); |
654 | /* | 704 | /* |
655 | * Each render_* function takes the actual height of the bar, and returns | 705 | * Each render_* function takes the actual height of the bar, and returns |
656 | * the ideal height. If the actual height is too short, the render function | 706 | * the ideal height. If the actual height is too short, the render function |
@@ -658,7 +708,7 @@ static uint32_t render_to_cairo(cairo_t *cairo, struct swaybar_output *output) { | |||
658 | * height is too tall, the render function should adapt its drawing to | 708 | * height is too tall, the render function should adapt its drawing to |
659 | * utilize the available space. | 709 | * utilize the available space. |
660 | */ | 710 | */ |
661 | double x = output->width * output->scale; | 711 | double x = output->width; |
662 | #if HAVE_TRAY | 712 | #if HAVE_TRAY |
663 | if (bar->tray) { | 713 | if (bar->tray) { |
664 | uint32_t h = render_tray(cairo, output, &x); | 714 | uint32_t h = render_tray(cairo, output, &x); |
@@ -666,19 +716,19 @@ static uint32_t render_to_cairo(cairo_t *cairo, struct swaybar_output *output) { | |||
666 | } | 716 | } |
667 | #endif | 717 | #endif |
668 | if (bar->status) { | 718 | if (bar->status) { |
669 | uint32_t h = render_status_line(cairo, output, &x); | 719 | uint32_t h = render_status_line(ctx, &x); |
670 | max_height = h > max_height ? h : max_height; | 720 | max_height = h > max_height ? h : max_height; |
671 | } | 721 | } |
672 | x = 0; | 722 | x = 0; |
673 | if (config->workspace_buttons) { | 723 | if (config->workspace_buttons) { |
674 | struct swaybar_workspace *ws; | 724 | struct swaybar_workspace *ws; |
675 | wl_list_for_each(ws, &output->workspaces, link) { | 725 | wl_list_for_each(ws, &output->workspaces, link) { |
676 | uint32_t h = render_workspace_button(cairo, output, ws, &x); | 726 | uint32_t h = render_workspace_button(ctx, ws, &x); |
677 | max_height = h > max_height ? h : max_height; | 727 | max_height = h > max_height ? h : max_height; |
678 | } | 728 | } |
679 | } | 729 | } |
680 | if (config->binding_mode_indicator) { | 730 | if (config->binding_mode_indicator) { |
681 | uint32_t h = render_binding_mode_indicator(cairo, output, x); | 731 | uint32_t h = render_binding_mode_indicator(ctx, x); |
682 | max_height = h > max_height ? h : max_height; | 732 | max_height = h > max_height ? h : max_height; |
683 | } | 733 | } |
684 | 734 | ||
@@ -708,26 +758,36 @@ void render_frame(struct swaybar_output *output) { | |||
708 | 758 | ||
709 | free_hotspots(&output->hotspots); | 759 | free_hotspots(&output->hotspots); |
710 | 760 | ||
761 | struct render_context ctx = { 0 }; | ||
762 | ctx.output = output; | ||
763 | |||
711 | cairo_surface_t *recorder = cairo_recording_surface_create( | 764 | cairo_surface_t *recorder = cairo_recording_surface_create( |
712 | CAIRO_CONTENT_COLOR_ALPHA, NULL); | 765 | CAIRO_CONTENT_COLOR_ALPHA, NULL); |
713 | cairo_t *cairo = cairo_create(recorder); | 766 | cairo_t *cairo = cairo_create(recorder); |
767 | cairo_scale(cairo, output->scale, output->scale); | ||
714 | cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); | 768 | cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); |
769 | ctx.cairo = cairo; | ||
770 | |||
715 | cairo_font_options_t *fo = cairo_font_options_create(); | 771 | cairo_font_options_t *fo = cairo_font_options_create(); |
716 | cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL); | 772 | cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL); |
773 | cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_GRAY); | ||
774 | ctx.textaa_safe = fo; | ||
717 | if (output->subpixel == WL_OUTPUT_SUBPIXEL_NONE) { | 775 | if (output->subpixel == WL_OUTPUT_SUBPIXEL_NONE) { |
718 | cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_GRAY); | 776 | ctx.textaa_sharp = ctx.textaa_safe; |
719 | } else { | 777 | } else { |
778 | fo = cairo_font_options_create(); | ||
779 | cairo_font_options_set_hint_style(fo, CAIRO_HINT_STYLE_FULL); | ||
720 | cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL); | 780 | cairo_font_options_set_antialias(fo, CAIRO_ANTIALIAS_SUBPIXEL); |
721 | cairo_font_options_set_subpixel_order(fo, | 781 | cairo_font_options_set_subpixel_order(fo, |
722 | to_cairo_subpixel_order(output->subpixel)); | 782 | to_cairo_subpixel_order(output->subpixel)); |
783 | ctx.textaa_sharp = fo; | ||
723 | } | 784 | } |
724 | cairo_set_font_options(cairo, fo); | 785 | |
725 | cairo_font_options_destroy(fo); | ||
726 | cairo_save(cairo); | 786 | cairo_save(cairo); |
727 | cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR); | 787 | cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR); |
728 | cairo_paint(cairo); | 788 | cairo_paint(cairo); |
729 | cairo_restore(cairo); | 789 | cairo_restore(cairo); |
730 | uint32_t height = render_to_cairo(cairo, output); | 790 | uint32_t height = render_to_cairo(&ctx); |
731 | int config_height = output->bar->config->height; | 791 | int config_height = output->bar->config->height; |
732 | if (config_height > 0) { | 792 | if (config_height > 0) { |
733 | height = config_height; | 793 | height = config_height; |
@@ -753,9 +813,7 @@ void render_frame(struct swaybar_output *output) { | |||
753 | output->width * output->scale, | 813 | output->width * output->scale, |
754 | output->height * output->scale); | 814 | output->height * output->scale); |
755 | if (!output->current_buffer) { | 815 | if (!output->current_buffer) { |
756 | cairo_surface_destroy(recorder); | 816 | goto cleanup; |
757 | cairo_destroy(cairo); | ||
758 | return; | ||
759 | } | 817 | } |
760 | cairo_t *shm = output->current_buffer->cairo; | 818 | cairo_t *shm = output->current_buffer->cairo; |
761 | 819 | ||
@@ -779,6 +837,12 @@ void render_frame(struct swaybar_output *output) { | |||
779 | 837 | ||
780 | wl_surface_commit(output->surface); | 838 | wl_surface_commit(output->surface); |
781 | } | 839 | } |
840 | |||
841 | cleanup: | ||
842 | if (ctx.textaa_sharp != ctx.textaa_safe) { | ||
843 | cairo_font_options_destroy(ctx.textaa_sharp); | ||
844 | } | ||
845 | cairo_font_options_destroy(ctx.textaa_safe); | ||
782 | cairo_surface_destroy(recorder); | 846 | cairo_surface_destroy(recorder); |
783 | cairo_destroy(cairo); | 847 | cairo_destroy(cairo); |
784 | } | 848 | } |
diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c index a5660f62..19f4beac 100644 --- a/swaybar/tray/item.c +++ b/swaybar/tray/item.c | |||
@@ -13,7 +13,7 @@ | |||
13 | #include "swaybar/tray/item.h" | 13 | #include "swaybar/tray/item.h" |
14 | #include "swaybar/tray/tray.h" | 14 | #include "swaybar/tray/tray.h" |
15 | #include "background-image.h" | 15 | #include "background-image.h" |
16 | #include "cairo.h" | 16 | #include "cairo_util.h" |
17 | #include "list.h" | 17 | #include "list.h" |
18 | #include "log.h" | 18 | #include "log.h" |
19 | #include "wlr-layer-shell-unstable-v1-client-protocol.h" | 19 | #include "wlr-layer-shell-unstable-v1-client-protocol.h" |
@@ -118,8 +118,13 @@ static int get_property_callback(sd_bus_message *msg, void *data, | |||
118 | 118 | ||
119 | int ret; | 119 | int ret; |
120 | if (sd_bus_message_is_method_error(msg, NULL)) { | 120 | if (sd_bus_message_is_method_error(msg, NULL)) { |
121 | sway_log(SWAY_ERROR, "%s %s: %s", sni->watcher_id, prop, | 121 | const sd_bus_error *err = sd_bus_message_get_error(msg); |
122 | sd_bus_message_get_error(msg)->message); | 122 | sway_log_importance_t log_lv = SWAY_ERROR; |
123 | if ((!strcmp(prop, "IconThemePath")) && | ||
124 | (!strcmp(err->name, SD_BUS_ERROR_UNKNOWN_PROPERTY))) { | ||
125 | log_lv = SWAY_DEBUG; | ||
126 | } | ||
127 | sway_log(log_lv, "%s %s: %s", sni->watcher_id, prop, err->message); | ||
123 | ret = sd_bus_message_get_errno(msg); | 128 | ret = sd_bus_message_get_errno(msg); |
124 | goto cleanup; | 129 | goto cleanup; |
125 | } | 130 | } |
diff --git a/swaymsg/main.c b/swaymsg/main.c index 60536e48..574d3b75 100644 --- a/swaymsg/main.c +++ b/swaymsg/main.c | |||
@@ -343,7 +343,7 @@ int main(int argc, char **argv) { | |||
343 | 343 | ||
344 | sway_log_init(SWAY_INFO, NULL); | 344 | sway_log_init(SWAY_INFO, NULL); |
345 | 345 | ||
346 | static struct option long_options[] = { | 346 | static const struct option long_options[] = { |
347 | {"help", no_argument, NULL, 'h'}, | 347 | {"help", no_argument, NULL, 'h'}, |
348 | {"monitor", no_argument, NULL, 'm'}, | 348 | {"monitor", no_argument, NULL, 'm'}, |
349 | {"pretty", no_argument, NULL, 'p'}, | 349 | {"pretty", no_argument, NULL, 'p'}, |
diff --git a/swaynag/config.c b/swaynag/config.c index ca7f4eb2..6db7cce5 100644 --- a/swaynag/config.c +++ b/swaynag/config.c | |||
@@ -51,7 +51,7 @@ int swaynag_parse_options(int argc, char **argv, struct swaynag *swaynag, | |||
51 | TO_PADDING_BTN, | 51 | TO_PADDING_BTN, |
52 | }; | 52 | }; |
53 | 53 | ||
54 | static struct option opts[] = { | 54 | static const struct option opts[] = { |
55 | {"button", required_argument, NULL, 'b'}, | 55 | {"button", required_argument, NULL, 'b'}, |
56 | {"button-no-terminal", required_argument, NULL, 'B'}, | 56 | {"button-no-terminal", required_argument, NULL, 'B'}, |
57 | {"button-dismiss", required_argument, NULL, 'z'}, | 57 | {"button-dismiss", required_argument, NULL, 'z'}, |
@@ -59,6 +59,7 @@ int swaynag_parse_options(int argc, char **argv, struct swaynag *swaynag, | |||
59 | {"config", required_argument, NULL, 'c'}, | 59 | {"config", required_argument, NULL, 'c'}, |
60 | {"debug", no_argument, NULL, 'd'}, | 60 | {"debug", no_argument, NULL, 'd'}, |
61 | {"edge", required_argument, NULL, 'e'}, | 61 | {"edge", required_argument, NULL, 'e'}, |
62 | {"layer", required_argument, NULL, 'y'}, | ||
62 | {"font", required_argument, NULL, 'f'}, | 63 | {"font", required_argument, NULL, 'f'}, |
63 | {"help", no_argument, NULL, 'h'}, | 64 | {"help", no_argument, NULL, 'h'}, |
64 | {"detailed-message", no_argument, NULL, 'l'}, | 65 | {"detailed-message", no_argument, NULL, 'l'}, |
@@ -104,6 +105,8 @@ int swaynag_parse_options(int argc, char **argv, struct swaynag *swaynag, | |||
104 | " -c, --config <path> Path to config file.\n" | 105 | " -c, --config <path> Path to config file.\n" |
105 | " -d, --debug Enable debugging.\n" | 106 | " -d, --debug Enable debugging.\n" |
106 | " -e, --edge top|bottom Set the edge to use.\n" | 107 | " -e, --edge top|bottom Set the edge to use.\n" |
108 | " -y, --layer overlay|top|bottom|background\n" | ||
109 | " Set the layer to use.\n" | ||
107 | " -f, --font <font> Set the font to use.\n" | 110 | " -f, --font <font> Set the font to use.\n" |
108 | " -h, --help Show help message and quit.\n" | 111 | " -h, --help Show help message and quit.\n" |
109 | " -l, --detailed-message Read a detailed message from stdin.\n" | 112 | " -l, --detailed-message Read a detailed message from stdin.\n" |
@@ -133,7 +136,7 @@ int swaynag_parse_options(int argc, char **argv, struct swaynag *swaynag, | |||
133 | 136 | ||
134 | optind = 1; | 137 | optind = 1; |
135 | while (1) { | 138 | while (1) { |
136 | int c = getopt_long(argc, argv, "b:B:z:Z:c:de:f:hlL:m:o:s:t:v", opts, NULL); | 139 | int c = getopt_long(argc, argv, "b:B:z:Z:c:de:y:f:hlL:m:o:s:t:v", opts, NULL); |
137 | if (c == -1) { | 140 | if (c == -1) { |
138 | break; | 141 | break; |
139 | } | 142 | } |
@@ -184,6 +187,24 @@ int swaynag_parse_options(int argc, char **argv, struct swaynag *swaynag, | |||
184 | } | 187 | } |
185 | } | 188 | } |
186 | break; | 189 | break; |
190 | case 'y': // Layer | ||
191 | if (type) { | ||
192 | if (strcmp(optarg, "background") == 0) { | ||
193 | type->layer = ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND; | ||
194 | } else if (strcmp(optarg, "bottom") == 0) { | ||
195 | type->layer = ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM; | ||
196 | } else if (strcmp(optarg, "top") == 0) { | ||
197 | type->layer = ZWLR_LAYER_SHELL_V1_LAYER_TOP; | ||
198 | } else if (strcmp(optarg, "overlay") == 0) { | ||
199 | type->layer = ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY; | ||
200 | } else { | ||
201 | fprintf(stderr, "Invalid layer: %s\n" | ||
202 | "Usage: --layer overlay|top|bottom|background\n", | ||
203 | optarg); | ||
204 | return EXIT_FAILURE; | ||
205 | } | ||
206 | } | ||
207 | break; | ||
187 | case 'f': // Font | 208 | case 'f': // Font |
188 | if (type) { | 209 | if (type) { |
189 | free(type->font); | 210 | free(type->font); |
diff --git a/swaynag/render.c b/swaynag/render.c index cf2cc9e0..d72f42c2 100644 --- a/swaynag/render.c +++ b/swaynag/render.c | |||
@@ -1,5 +1,5 @@ | |||
1 | #include <stdint.h> | 1 | #include <stdint.h> |
2 | #include "cairo.h" | 2 | #include "cairo_util.h" |
3 | #include "log.h" | 3 | #include "log.h" |
4 | #include "pango.h" | 4 | #include "pango.h" |
5 | #include "pool-buffer.h" | 5 | #include "pool-buffer.h" |
@@ -10,19 +10,19 @@ | |||
10 | static uint32_t render_message(cairo_t *cairo, struct swaynag *swaynag) { | 10 | static uint32_t render_message(cairo_t *cairo, struct swaynag *swaynag) { |
11 | int text_width, text_height; | 11 | int text_width, text_height; |
12 | get_text_size(cairo, swaynag->type->font, &text_width, &text_height, NULL, | 12 | get_text_size(cairo, swaynag->type->font, &text_width, &text_height, NULL, |
13 | swaynag->scale, true, "%s", swaynag->message); | 13 | 1, true, "%s", swaynag->message); |
14 | 14 | ||
15 | int padding = swaynag->type->message_padding * swaynag->scale; | 15 | int padding = swaynag->type->message_padding; |
16 | 16 | ||
17 | uint32_t ideal_height = text_height + padding * 2; | 17 | uint32_t ideal_height = text_height + padding * 2; |
18 | uint32_t ideal_surface_height = ideal_height / swaynag->scale; | 18 | uint32_t ideal_surface_height = ideal_height; |
19 | if (swaynag->height < ideal_surface_height) { | 19 | if (swaynag->height < ideal_surface_height) { |
20 | return ideal_surface_height; | 20 | return ideal_surface_height; |
21 | } | 21 | } |
22 | 22 | ||
23 | cairo_set_source_u32(cairo, swaynag->type->text); | 23 | cairo_set_source_u32(cairo, swaynag->type->text); |
24 | cairo_move_to(cairo, padding, (int)(ideal_height - text_height) / 2); | 24 | cairo_move_to(cairo, padding, (int)(ideal_height - text_height) / 2); |
25 | pango_printf(cairo, swaynag->type->font, swaynag->scale, false, | 25 | render_text(cairo, swaynag->type->font, 1, false, |
26 | "%s", swaynag->message); | 26 | "%s", swaynag->message); |
27 | 27 | ||
28 | return ideal_surface_height; | 28 | return ideal_surface_height; |
@@ -32,10 +32,10 @@ static void render_details_scroll_button(cairo_t *cairo, | |||
32 | struct swaynag *swaynag, struct swaynag_button *button) { | 32 | struct swaynag *swaynag, struct swaynag_button *button) { |
33 | int text_width, text_height; | 33 | int text_width, text_height; |
34 | get_text_size(cairo, swaynag->type->font, &text_width, &text_height, NULL, | 34 | get_text_size(cairo, swaynag->type->font, &text_width, &text_height, NULL, |
35 | swaynag->scale, true, "%s", button->text); | 35 | 1, true, "%s", button->text); |
36 | 36 | ||
37 | int border = swaynag->type->button_border_thickness * swaynag->scale; | 37 | int border = swaynag->type->button_border_thickness; |
38 | int padding = swaynag->type->button_padding * swaynag->scale; | 38 | int padding = swaynag->type->button_padding; |
39 | 39 | ||
40 | cairo_set_source_u32(cairo, swaynag->type->details_background); | 40 | cairo_set_source_u32(cairo, swaynag->type->details_background); |
41 | cairo_rectangle(cairo, button->x, button->y, | 41 | cairo_rectangle(cairo, button->x, button->y, |
@@ -50,7 +50,7 @@ static void render_details_scroll_button(cairo_t *cairo, | |||
50 | cairo_set_source_u32(cairo, swaynag->type->button_text); | 50 | cairo_set_source_u32(cairo, swaynag->type->button_text); |
51 | cairo_move_to(cairo, button->x + border + padding, | 51 | cairo_move_to(cairo, button->x + border + padding, |
52 | button->y + border + (button->height - text_height) / 2); | 52 | button->y + border + (button->height - text_height) / 2); |
53 | pango_printf(cairo, swaynag->type->font, swaynag->scale, true, | 53 | render_text(cairo, swaynag->type->font, 1, true, |
54 | "%s", button->text); | 54 | "%s", button->text); |
55 | } | 55 | } |
56 | 56 | ||
@@ -58,33 +58,33 @@ static int get_detailed_scroll_button_width(cairo_t *cairo, | |||
58 | struct swaynag *swaynag) { | 58 | struct swaynag *swaynag) { |
59 | int up_width, down_width, temp_height; | 59 | int up_width, down_width, temp_height; |
60 | get_text_size(cairo, swaynag->type->font, &up_width, &temp_height, NULL, | 60 | get_text_size(cairo, swaynag->type->font, &up_width, &temp_height, NULL, |
61 | swaynag->scale, true, | 61 | 1, true, |
62 | "%s", swaynag->details.button_up.text); | 62 | "%s", swaynag->details.button_up.text); |
63 | get_text_size(cairo, swaynag->type->font, &down_width, &temp_height, NULL, | 63 | get_text_size(cairo, swaynag->type->font, &down_width, &temp_height, NULL, |
64 | swaynag->scale, true, | 64 | 1, true, |
65 | "%s", swaynag->details.button_down.text); | 65 | "%s", swaynag->details.button_down.text); |
66 | 66 | ||
67 | int text_width = up_width > down_width ? up_width : down_width; | 67 | int text_width = up_width > down_width ? up_width : down_width; |
68 | int border = swaynag->type->button_border_thickness * swaynag->scale; | 68 | int border = swaynag->type->button_border_thickness; |
69 | int padding = swaynag->type->button_padding * swaynag->scale; | 69 | int padding = swaynag->type->button_padding; |
70 | 70 | ||
71 | return text_width + border * 2 + padding * 2; | 71 | return text_width + border * 2 + padding * 2; |
72 | } | 72 | } |
73 | 73 | ||
74 | static uint32_t render_detailed(cairo_t *cairo, struct swaynag *swaynag, | 74 | static uint32_t render_detailed(cairo_t *cairo, struct swaynag *swaynag, |
75 | uint32_t y) { | 75 | uint32_t y) { |
76 | uint32_t width = swaynag->width * swaynag->scale; | 76 | uint32_t width = swaynag->width; |
77 | 77 | ||
78 | int border = swaynag->type->details_border_thickness * swaynag->scale; | 78 | int border = swaynag->type->details_border_thickness; |
79 | int padding = swaynag->type->message_padding * swaynag->scale; | 79 | int padding = swaynag->type->message_padding; |
80 | int decor = padding + border; | 80 | int decor = padding + border; |
81 | 81 | ||
82 | swaynag->details.x = decor; | 82 | swaynag->details.x = decor; |
83 | swaynag->details.y = y * swaynag->scale + decor; | 83 | swaynag->details.y = y + decor; |
84 | swaynag->details.width = width - decor * 2; | 84 | swaynag->details.width = width - decor * 2; |
85 | 85 | ||
86 | PangoLayout *layout = get_pango_layout(cairo, swaynag->type->font, | 86 | PangoLayout *layout = get_pango_layout(cairo, swaynag->type->font, |
87 | swaynag->details.message, swaynag->scale, false); | 87 | swaynag->details.message, 1, false); |
88 | pango_layout_set_width(layout, | 88 | pango_layout_set_width(layout, |
89 | (swaynag->details.width - padding * 2) * PANGO_SCALE); | 89 | (swaynag->details.width - padding * 2) * PANGO_SCALE); |
90 | pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); | 90 | pango_layout_set_wrap(layout, PANGO_WRAP_WORD_CHAR); |
@@ -164,7 +164,7 @@ static uint32_t render_detailed(cairo_t *cairo, struct swaynag *swaynag, | |||
164 | pango_cairo_show_layout(cairo, layout); | 164 | pango_cairo_show_layout(cairo, layout); |
165 | g_object_unref(layout); | 165 | g_object_unref(layout); |
166 | 166 | ||
167 | return ideal_height / swaynag->scale; | 167 | return ideal_height; |
168 | } | 168 | } |
169 | 169 | ||
170 | static uint32_t render_button(cairo_t *cairo, struct swaynag *swaynag, | 170 | static uint32_t render_button(cairo_t *cairo, struct swaynag *swaynag, |
@@ -173,13 +173,13 @@ static uint32_t render_button(cairo_t *cairo, struct swaynag *swaynag, | |||
173 | 173 | ||
174 | int text_width, text_height; | 174 | int text_width, text_height; |
175 | get_text_size(cairo, swaynag->type->font, &text_width, &text_height, NULL, | 175 | get_text_size(cairo, swaynag->type->font, &text_width, &text_height, NULL, |
176 | swaynag->scale, true, "%s", button->text); | 176 | 1, true, "%s", button->text); |
177 | 177 | ||
178 | int border = swaynag->type->button_border_thickness * swaynag->scale; | 178 | int border = swaynag->type->button_border_thickness; |
179 | int padding = swaynag->type->button_padding * swaynag->scale; | 179 | int padding = swaynag->type->button_padding; |
180 | 180 | ||
181 | uint32_t ideal_height = text_height + padding * 2 + border * 2; | 181 | uint32_t ideal_height = text_height + padding * 2 + border * 2; |
182 | uint32_t ideal_surface_height = ideal_height / swaynag->scale; | 182 | uint32_t ideal_surface_height = ideal_height; |
183 | if (swaynag->height < ideal_surface_height) { | 183 | if (swaynag->height < ideal_surface_height) { |
184 | return ideal_surface_height; | 184 | return ideal_surface_height; |
185 | } | 185 | } |
@@ -201,7 +201,7 @@ static uint32_t render_button(cairo_t *cairo, struct swaynag *swaynag, | |||
201 | 201 | ||
202 | cairo_set_source_u32(cairo, swaynag->type->button_text); | 202 | cairo_set_source_u32(cairo, swaynag->type->button_text); |
203 | cairo_move_to(cairo, button->x + padding, button->y + padding); | 203 | cairo_move_to(cairo, button->x + padding, button->y + padding); |
204 | pango_printf(cairo, swaynag->type->font, swaynag->scale, true, | 204 | render_text(cairo, swaynag->type->font, 1, true, |
205 | "%s", button->text); | 205 | "%s", button->text); |
206 | 206 | ||
207 | *x = button->x - border; | 207 | *x = button->x - border; |
@@ -220,13 +220,12 @@ static uint32_t render_to_cairo(cairo_t *cairo, struct swaynag *swaynag) { | |||
220 | max_height = h > max_height ? h : max_height; | 220 | max_height = h > max_height ? h : max_height; |
221 | 221 | ||
222 | int x = swaynag->width - swaynag->type->button_margin_right; | 222 | int x = swaynag->width - swaynag->type->button_margin_right; |
223 | x *= swaynag->scale; | ||
224 | for (int i = 0; i < swaynag->buttons->length; i++) { | 223 | for (int i = 0; i < swaynag->buttons->length; i++) { |
225 | h = render_button(cairo, swaynag, i, &x); | 224 | h = render_button(cairo, swaynag, i, &x); |
226 | max_height = h > max_height ? h : max_height; | 225 | max_height = h > max_height ? h : max_height; |
227 | x -= swaynag->type->button_gap * swaynag->scale; | 226 | x -= swaynag->type->button_gap; |
228 | if (i == 0) { | 227 | if (i == 0) { |
229 | x -= swaynag->type->button_gap_close * swaynag->scale; | 228 | x -= swaynag->type->button_gap_close; |
230 | } | 229 | } |
231 | } | 230 | } |
232 | 231 | ||
@@ -235,14 +234,14 @@ static uint32_t render_to_cairo(cairo_t *cairo, struct swaynag *swaynag) { | |||
235 | max_height = h > max_height ? h : max_height; | 234 | max_height = h > max_height ? h : max_height; |
236 | } | 235 | } |
237 | 236 | ||
238 | int border = swaynag->type->bar_border_thickness * swaynag->scale; | 237 | int border = swaynag->type->bar_border_thickness; |
239 | if (max_height > swaynag->height) { | 238 | if (max_height > swaynag->height) { |
240 | max_height += border; | 239 | max_height += border; |
241 | } | 240 | } |
242 | cairo_set_source_u32(cairo, swaynag->type->border_bottom); | 241 | cairo_set_source_u32(cairo, swaynag->type->border_bottom); |
243 | cairo_rectangle(cairo, 0, | 242 | cairo_rectangle(cairo, 0, |
244 | swaynag->height * swaynag->scale - border, | 243 | swaynag->height - border, |
245 | swaynag->width * swaynag->scale, | 244 | swaynag->width, |
246 | border); | 245 | border); |
247 | cairo_fill(cairo); | 246 | cairo_fill(cairo); |
248 | 247 | ||
@@ -257,6 +256,7 @@ void render_frame(struct swaynag *swaynag) { | |||
257 | cairo_surface_t *recorder = cairo_recording_surface_create( | 256 | cairo_surface_t *recorder = cairo_recording_surface_create( |
258 | CAIRO_CONTENT_COLOR_ALPHA, NULL); | 257 | CAIRO_CONTENT_COLOR_ALPHA, NULL); |
259 | cairo_t *cairo = cairo_create(recorder); | 258 | cairo_t *cairo = cairo_create(recorder); |
259 | cairo_scale(cairo, swaynag->scale, swaynag->scale); | ||
260 | cairo_save(cairo); | 260 | cairo_save(cairo); |
261 | cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR); | 261 | cairo_set_operator(cairo, CAIRO_OPERATOR_CLEAR); |
262 | cairo_paint(cairo); | 262 | cairo_paint(cairo); |
diff --git a/swaynag/swaynag.1.scd b/swaynag/swaynag.1.scd index 4a03469e..1cc85db7 100644 --- a/swaynag/swaynag.1.scd +++ b/swaynag/swaynag.1.scd | |||
@@ -48,6 +48,9 @@ _swaynag_ [options...] | |||
48 | *-e, --edge* top|bottom | 48 | *-e, --edge* top|bottom |
49 | Set the edge to use. | 49 | Set the edge to use. |
50 | 50 | ||
51 | *-y, --layer* overlay|top|bottom|background | ||
52 | Set the layer to use. | ||
53 | |||
51 | *-f, --font* <font> | 54 | *-f, --font* <font> |
52 | Set the font to use. | 55 | Set the font to use. |
53 | 56 | ||
diff --git a/swaynag/swaynag.5.scd b/swaynag/swaynag.5.scd index a078a4d7..3c367d0f 100644 --- a/swaynag/swaynag.5.scd +++ b/swaynag/swaynag.5.scd | |||
@@ -53,7 +53,7 @@ The following sizing options can also be set: | |||
53 | *message-padding=<padding>* | 53 | *message-padding=<padding>* |
54 | Set the padding for the message. | 54 | Set the padding for the message. |
55 | 55 | ||
56 | *details-gackground=<color>* | 56 | *details-background=<color>* |
57 | The background color for the details. | 57 | The background color for the details. |
58 | 58 | ||
59 | *details-border-size=<size>* | 59 | *details-border-size=<size>* |
@@ -79,6 +79,9 @@ Additionally, the following options can be assigned a default per-type: | |||
79 | *edge=top|bottom* | 79 | *edge=top|bottom* |
80 | Set the edge to use. | 80 | Set the edge to use. |
81 | 81 | ||
82 | *layer=overlay|top|bottom|background* | ||
83 | Set the layer to use. | ||
84 | |||
82 | *font=<font>* | 85 | *font=<font>* |
83 | Set the font to use. | 86 | Set the font to use. |
84 | 87 | ||
diff --git a/swaynag/swaynag.c b/swaynag/swaynag.c index d9bec368..6d4a7a58 100644 --- a/swaynag/swaynag.c +++ b/swaynag/swaynag.c | |||
@@ -30,8 +30,8 @@ static bool terminal_execute(char *terminal, char *command) { | |||
30 | chmod(fname, S_IRUSR | S_IWUSR | S_IXUSR); | 30 | chmod(fname, S_IRUSR | S_IWUSR | S_IXUSR); |
31 | char *cmd = malloc(sizeof(char) * (strlen(terminal) + strlen(" -e ") + strlen(fname) + 1)); | 31 | char *cmd = malloc(sizeof(char) * (strlen(terminal) + strlen(" -e ") + strlen(fname) + 1)); |
32 | sprintf(cmd, "%s -e %s", terminal, fname); | 32 | sprintf(cmd, "%s -e %s", terminal, fname); |
33 | execl("/bin/sh", "/bin/sh", "-c", cmd, NULL); | 33 | execlp("sh", "sh", "-c", cmd, NULL); |
34 | sway_log_errno(SWAY_ERROR, "Failed to run command, execl() returned."); | 34 | sway_log_errno(SWAY_ERROR, "Failed to run command, execlp() returned."); |
35 | free(cmd); | 35 | free(cmd); |
36 | return false; | 36 | return false; |
37 | } | 37 | } |
@@ -69,8 +69,8 @@ static void swaynag_button_execute(struct swaynag *swaynag, | |||
69 | sway_log(SWAY_DEBUG, | 69 | sway_log(SWAY_DEBUG, |
70 | "$TERMINAL not found. Running directly"); | 70 | "$TERMINAL not found. Running directly"); |
71 | } | 71 | } |
72 | execl("/bin/sh", "/bin/sh", "-c", button->action, NULL); | 72 | execlp("sh", "sh", "-c", button->action, NULL); |
73 | sway_log_errno(SWAY_DEBUG, "execl failed"); | 73 | sway_log_errno(SWAY_DEBUG, "execlp failed"); |
74 | _exit(EXIT_FAILURE); | 74 | _exit(EXIT_FAILURE); |
75 | } | 75 | } |
76 | } | 76 | } |
@@ -103,7 +103,7 @@ static void layer_surface_closed(void *data, | |||
103 | swaynag_destroy(swaynag); | 103 | swaynag_destroy(swaynag); |
104 | } | 104 | } |
105 | 105 | ||
106 | static struct zwlr_layer_surface_v1_listener layer_surface_listener = { | 106 | static const struct zwlr_layer_surface_v1_listener layer_surface_listener = { |
107 | .configure = layer_surface_configure, | 107 | .configure = layer_surface_configure, |
108 | .closed = layer_surface_closed, | 108 | .closed = layer_surface_closed, |
109 | }; | 109 | }; |
@@ -124,7 +124,7 @@ static void surface_enter(void *data, struct wl_surface *surface, | |||
124 | }; | 124 | }; |
125 | } | 125 | } |
126 | 126 | ||
127 | static struct wl_surface_listener surface_listener = { | 127 | static const struct wl_surface_listener surface_listener = { |
128 | .enter = surface_enter, | 128 | .enter = surface_enter, |
129 | .leave = nop, | 129 | .leave = nop, |
130 | }; | 130 | }; |
@@ -178,6 +178,8 @@ static void wl_pointer_enter(void *data, struct wl_pointer *wl_pointer, | |||
178 | wl_fixed_t surface_x, wl_fixed_t surface_y) { | 178 | wl_fixed_t surface_x, wl_fixed_t surface_y) { |
179 | struct swaynag_seat *seat = data; | 179 | struct swaynag_seat *seat = data; |
180 | struct swaynag_pointer *pointer = &seat->pointer; | 180 | struct swaynag_pointer *pointer = &seat->pointer; |
181 | pointer->x = wl_fixed_to_int(surface_x); | ||
182 | pointer->y = wl_fixed_to_int(surface_y); | ||
181 | pointer->serial = serial; | 183 | pointer->serial = serial; |
182 | update_cursor(seat); | 184 | update_cursor(seat); |
183 | } | 185 | } |
@@ -198,8 +200,8 @@ static void wl_pointer_button(void *data, struct wl_pointer *wl_pointer, | |||
198 | return; | 200 | return; |
199 | } | 201 | } |
200 | 202 | ||
201 | double x = seat->pointer.x * swaynag->scale; | 203 | double x = seat->pointer.x; |
202 | double y = seat->pointer.y * swaynag->scale; | 204 | double y = seat->pointer.y; |
203 | for (int i = 0; i < swaynag->buttons->length; i++) { | 205 | for (int i = 0; i < swaynag->buttons->length; i++) { |
204 | struct swaynag_button *nagbutton = swaynag->buttons->items[i]; | 206 | struct swaynag_button *nagbutton = swaynag->buttons->items[i]; |
205 | if (x >= nagbutton->x | 207 | if (x >= nagbutton->x |
@@ -263,7 +265,7 @@ static void wl_pointer_axis(void *data, struct wl_pointer *wl_pointer, | |||
263 | render_frame(swaynag); | 265 | render_frame(swaynag); |
264 | } | 266 | } |
265 | 267 | ||
266 | static struct wl_pointer_listener pointer_listener = { | 268 | static const struct wl_pointer_listener pointer_listener = { |
267 | .enter = wl_pointer_enter, | 269 | .enter = wl_pointer_enter, |
268 | .leave = nop, | 270 | .leave = nop, |
269 | .motion = wl_pointer_motion, | 271 | .motion = wl_pointer_motion, |
@@ -289,7 +291,7 @@ static void seat_handle_capabilities(void *data, struct wl_seat *wl_seat, | |||
289 | } | 291 | } |
290 | } | 292 | } |
291 | 293 | ||
292 | const struct wl_seat_listener seat_listener = { | 294 | static const struct wl_seat_listener seat_listener = { |
293 | .capabilities = seat_handle_capabilities, | 295 | .capabilities = seat_handle_capabilities, |
294 | .name = nop, | 296 | .name = nop, |
295 | }; | 297 | }; |
@@ -305,7 +307,7 @@ static void output_scale(void *data, struct wl_output *output, | |||
305 | } | 307 | } |
306 | } | 308 | } |
307 | 309 | ||
308 | static struct wl_output_listener output_listener = { | 310 | static const struct wl_output_listener output_listener = { |
309 | .geometry = nop, | 311 | .geometry = nop, |
310 | .mode = nop, | 312 | .mode = nop, |
311 | .done = nop, | 313 | .done = nop, |
@@ -327,7 +329,7 @@ static void xdg_output_handle_name(void *data, | |||
327 | swaynag_output->swaynag->querying_outputs--; | 329 | swaynag_output->swaynag->querying_outputs--; |
328 | } | 330 | } |
329 | 331 | ||
330 | static struct zxdg_output_v1_listener xdg_output_listener = { | 332 | static const struct zxdg_output_v1_listener xdg_output_listener = { |
331 | .logical_position = nop, | 333 | .logical_position = nop, |
332 | .logical_size = nop, | 334 | .logical_size = nop, |
333 | .done = nop, | 335 | .done = nop, |
@@ -474,7 +476,8 @@ void swaynag_setup(struct swaynag *swaynag) { | |||
474 | swaynag->layer_surface = zwlr_layer_shell_v1_get_layer_surface( | 476 | swaynag->layer_surface = zwlr_layer_shell_v1_get_layer_surface( |
475 | swaynag->layer_shell, swaynag->surface, | 477 | swaynag->layer_shell, swaynag->surface, |
476 | swaynag->output ? swaynag->output->wl_output : NULL, | 478 | swaynag->output ? swaynag->output->wl_output : NULL, |
477 | ZWLR_LAYER_SHELL_V1_LAYER_TOP, "swaynag"); | 479 | swaynag->type->layer, |
480 | "swaynag"); | ||
478 | assert(swaynag->layer_surface); | 481 | assert(swaynag->layer_surface); |
479 | zwlr_layer_surface_v1_add_listener(swaynag->layer_surface, | 482 | zwlr_layer_surface_v1_add_listener(swaynag->layer_surface, |
480 | &layer_surface_listener, swaynag); | 483 | &layer_surface_listener, swaynag); |
diff --git a/swaynag/types.c b/swaynag/types.c index fa045532..7bef0f87 100644 --- a/swaynag/types.c +++ b/swaynag/types.c | |||
@@ -26,6 +26,7 @@ struct swaynag_type *swaynag_type_new(const char *name) { | |||
26 | type->button_gap_close = -1; | 26 | type->button_gap_close = -1; |
27 | type->button_margin_right = -1; | 27 | type->button_margin_right = -1; |
28 | type->button_padding = -1; | 28 | type->button_padding = -1; |
29 | type->layer = -1; | ||
29 | return type; | 30 | return type; |
30 | } | 31 | } |
31 | 32 | ||
@@ -35,6 +36,7 @@ void swaynag_types_add_default(list_t *types) { | |||
35 | type_defaults->anchors = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | 36 | type_defaults->anchors = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP |
36 | | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | 37 | | ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT |
37 | | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; | 38 | | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; |
39 | type_defaults->layer = ZWLR_LAYER_SHELL_V1_LAYER_TOP; | ||
38 | type_defaults->button_background = 0x333333FF; | 40 | type_defaults->button_background = 0x333333FF; |
39 | type_defaults->details_background = 0x333333FF; | 41 | type_defaults->details_background = 0x333333FF; |
40 | type_defaults->background = 0x323232FF; | 42 | type_defaults->background = 0x323232FF; |
@@ -100,6 +102,10 @@ void swaynag_type_merge(struct swaynag_type *dest, struct swaynag_type *src) { | |||
100 | dest->anchors = src->anchors; | 102 | dest->anchors = src->anchors; |
101 | } | 103 | } |
102 | 104 | ||
105 | if (src->layer >= 0) { | ||
106 | dest->layer = src->layer; | ||
107 | } | ||
108 | |||
103 | // Colors | 109 | // Colors |
104 | if (src->button_background > 0) { | 110 | if (src->button_background > 0) { |
105 | dest->button_background = src->button_background; | 111 | dest->button_background = src->button_background; |