diff options
68 files changed, 1086 insertions, 738 deletions
diff --git a/README.bg.md b/README.bg.md index e2753656..9d91dfa4 100644 --- a/README.bg.md +++ b/README.bg.md | |||
@@ -5,8 +5,6 @@ | |||
5 | [IRC канала](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway на | 5 | [IRC канала](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway на |
6 | irc.freenode.net). | 6 | irc.freenode.net). |
7 | 7 | ||
8 | **Внимание**: На този етап в Sway няма да бъдат добавяни нови функции, докато не приключим с интеграцията на Sway и wlroots. Все още се оправят бъгове. | ||
9 | |||
10 | [![](https://sr.ht/ICd5.png)](https://sr.ht/ICd5.png) | 8 | [![](https://sr.ht/ICd5.png)](https://sr.ht/ICd5.png) |
11 | 9 | ||
12 | Ако желаете, може да дарите на [Patreon страницата на автора](https://patreon.com/sircmpwn), което ще помогне за цялостното здраве и развитие на проекта. | 10 | Ако желаете, може да дарите на [Patreon страницата на автора](https://patreon.com/sircmpwn), което ще помогне за цялостното здраве и развитие на проекта. |
@@ -21,14 +19,6 @@ irc.freenode.net). | |||
21 | Версии подписани с ключ [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) | 19 | Версии подписани с ключ [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) |
22 | и публикувани в [GitHub](https://github.com/swaywm/sway/releases). | 20 | и публикувани в [GitHub](https://github.com/swaywm/sway/releases). |
23 | 21 | ||
24 | ## Статус | ||
25 | |||
26 | - [i3 поддръжка](https://github.com/swaywm/sway/issues/2) | ||
27 | - [i3-bar поддръжка](https://github.com/swaywm/sway/issues/343) | ||
28 | - [i3-gaps поддръжка](https://github.com/swaywm/sway/issues/307) | ||
29 | - [IPC поддръжка](https://github.com/swaywm/sway/issues/98) | ||
30 | - [Сигурност](https://github.com/swaywm/sway/issues/984) | ||
31 | |||
32 | ## Инсталация | 22 | ## Инсталация |
33 | 23 | ||
34 | ### От пакети | 24 | ### От пакети |
diff --git a/README.de.md b/README.de.md index 9d8a41ce..9e591022 100644 --- a/README.de.md +++ b/README.de.md | |||
@@ -28,14 +28,6 @@ Neue Versionen werden mit | |||
28 | [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) | 28 | [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) |
29 | signiert und [auf Github](https://github.com/swaywm/sway/releases) veröffentlicht. | 29 | signiert und [auf Github](https://github.com/swaywm/sway/releases) veröffentlicht. |
30 | 30 | ||
31 | ## Status | ||
32 | |||
33 | - [i3-Features](https://github.com/swaywm/sway/issues/2) | ||
34 | - [IPC-Features](https://github.com/swaywm/sway/issues/98) | ||
35 | - [i3bar-Features](https://github.com/swaywm/sway/issues/343) | ||
36 | - [i3-gaps-Features](https://github.com/swaywm/sway/issues/307) | ||
37 | - [Sicherheitsfeatures](https://github.com/swaywm/sway/issues/984) | ||
38 | |||
39 | ## Installation | 31 | ## Installation |
40 | 32 | ||
41 | ### Als Paket | 33 | ### Als Paket |
diff --git a/README.el.md b/README.el.md index 53fdd2d9..d56728a0 100644 --- a/README.el.md +++ b/README.el.md | |||
@@ -23,14 +23,6 @@ To username μου στο Freenode είναι kon14 και θα με βρείτ | |||
23 | 23 | ||
24 | Οι εκδόσεις υπογράφονται ως [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) και δημοσιεύονται στο [GitHub](https://github.com/swaywm/sway/releases). | 24 | Οι εκδόσεις υπογράφονται ως [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) και δημοσιεύονται στο [GitHub](https://github.com/swaywm/sway/releases). |
25 | 25 | ||
26 | ## Κατάσταση | ||
27 | |||
28 | - [Υποστήριξη δυνατοτήτων του i3](https://github.com/swaywm/sway/issues/2) | ||
29 | - [Υποστήριξη δυνατοτήτων IPC](https://github.com/swaywm/sway/issues/98) | ||
30 | - [Υποστήριξη δυνατοτήτων i3bar](https://github.com/swaywm/sway/issues/343) | ||
31 | - [Υποστήριξη δυνατοτήτων i3-gaps](https://github.com/swaywm/sway/issues/307) | ||
32 | - [Δυνατότητες Ασφαλείας](https://github.com/swaywm/sway/issues/984) | ||
33 | |||
34 | ## Εγκατάσταση | 26 | ## Εγκατάσταση |
35 | 27 | ||
36 | ### Από Πακέτα | 28 | ### Από Πακέτα |
diff --git a/README.fr.md b/README.fr.md index 0a9697b8..629aef95 100644 --- a/README.fr.md +++ b/README.fr.md | |||
@@ -24,14 +24,6 @@ maintenance de Sway. | |||
24 | Les nouvelles versions sont signées avec [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) | 24 | Les nouvelles versions sont signées avec [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) |
25 | et publiées [sur GitHub](https://github.com/swaywm/sway/releases). | 25 | et publiées [sur GitHub](https://github.com/swaywm/sway/releases). |
26 | 26 | ||
27 | ## Statut | ||
28 | |||
29 | - [support des fonctionnalités d'i3](https://github.com/swaywm/sway/issues/2) | ||
30 | - [support des fonctionnalités d'IPC](https://github.com/swaywm/sway/issues/98) | ||
31 | - [support des fonctionnalités d'i3bar](https://github.com/swaywm/sway/issues/343) | ||
32 | - [support des fonctionnalités d'i3-gaps](https://github.com/swaywm/sway/issues/307) | ||
33 | - [fonctionnalités de sécurité](https://github.com/swaywm/sway/issues/984) | ||
34 | |||
35 | ## Installation | 27 | ## Installation |
36 | 28 | ||
37 | ### À partir de paquets | 29 | ### À partir de paquets |
diff --git a/README.it.md b/README.it.md index 653e6aea..a7e175c1 100644 --- a/README.it.md +++ b/README.it.md | |||
@@ -25,14 +25,6 @@ Questa traduzione non è ancora completa. [Clicca qui per maggiori informazioni] | |||
25 | Le release sono firmate con [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) | 25 | Le release sono firmate con [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) |
26 | e pubblicate [su GitHub](https://github.com/swaywm/sway/releases). | 26 | e pubblicate [su GitHub](https://github.com/swaywm/sway/releases). |
27 | 27 | ||
28 | ## Status | ||
29 | |||
30 | - [supporto funzionalità i3](https://github.com/swaywm/sway/issues/2) | ||
31 | - [supporto funzionalità IPC](https://github.com/swaywm/sway/issues/98) | ||
32 | - [supporto funzionalità i3bar](https://github.com/swaywm/sway/issues/343) | ||
33 | - [supporto funzionalità i3-gaps](https://github.com/swaywm/sway/issues/307) | ||
34 | - [sicurezza](https://github.com/swaywm/sway/issues/984) | ||
35 | |||
36 | ## Installazione | 28 | ## Installazione |
37 | 29 | ||
38 | ### Dai pacchetti | 30 | ### Dai pacchetti |
diff --git a/README.ja.md b/README.ja.md index b0488c53..396e0a72 100644 --- a/README.ja.md +++ b/README.ja.md | |||
@@ -5,27 +5,18 @@ i3互換な[Wayland](http://wayland.freedesktop.org/)コンポジタです。 | |||
5 | [FAQ](https://github.com/swaywm/sway/wiki)も合わせてご覧ください。 | 5 | [FAQ](https://github.com/swaywm/sway/wiki)も合わせてご覧ください。 |
6 | [IRC チャンネル](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on irc.freenode.net)もあります。 | 6 | [IRC チャンネル](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on irc.freenode.net)もあります。 |
7 | 7 | ||
8 | **注意**: Swayは現在*凍結中*であり、wlcからwlrootsへの移植が完了するまで新たな機能は追加されません。2018年9月以降に発見されるバグは0.15では対応されません。詳しくは[この記事](https://drewdevault.com/2017/10/09/Future-of-sway.html)をご覧ください。wlrootsとの統合状況については、[このチケット](https://github.com/swaywm/sway/issues/1390)をご覧ください。 | ||
9 | |||
10 | [![](https://sr.ht/ICd5.png)](https://sr.ht/ICd5.png) | 8 | [![](https://sr.ht/ICd5.png)](https://sr.ht/ICd5.png) |
11 | 9 | ||
12 | Swayの開発を支援したい場合は、[SirCmpwnのPatreon](https://patreon.com/sircmpwn)や、特定の機能に対する[報奨金のページ](https://github.com/swaywm/sway/issues/986)から寄付ができます。誰でも報奨金を請求できますし、自分の欲しい機能に報奨金を懸ける事も出来ます。またSwayのメンテナンスを支援するには、Patreonがより有用です。 | 10 | Swayの開発を支援したい場合は、[SirCmpwnのPatreon](https://patreon.com/sircmpwn)や、特定の機能に対する[報奨金のページ](https://github.com/swaywm/sway/issues/986)から寄付ができます。誰でも報奨金を請求できますし、自分の欲しい機能に報奨金を懸ける事も出来ます。またSwayのメンテナンスを支援するには、Patreonがより有用です。 |
13 | 11 | ||
14 | ## 日本語サポート | 12 | ## 日本語サポート |
13 | |||
15 | SirCmpwnは、日本語でのサポートをIRCとGitHubで行います。タイムゾーンはUTC-4です。 | 14 | SirCmpwnは、日本語でのサポートをIRCとGitHubで行います。タイムゾーンはUTC-4です。 |
16 | 15 | ||
17 | ## リリースの署名 | 16 | ## リリースの署名 |
18 | 17 | ||
19 | Swayのリリースは[B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)で署名され、[GitHub](https://github.com/swaywm/sway/releases)で公開されています。 | 18 | Swayのリリースは[B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)で署名され、[GitHub](https://github.com/swaywm/sway/releases)で公開されています。 |
20 | 19 | ||
21 | ## 開発状況 | ||
22 | |||
23 | - [i3の機能のサポート](https://github.com/swaywm/sway/issues/2) | ||
24 | - [IPCの機能のサポート](https://github.com/swaywm/sway/issues/98) | ||
25 | - [i3barの機能のサポート](https://github.com/swaywm/sway/issues/343) | ||
26 | - [i3-gapsの機能のサポート](https://github.com/swaywm/sway/issues/307) | ||
27 | - [セキュリティ機能](https://github.com/swaywm/sway/issues/984) | ||
28 | |||
29 | ## インストール | 20 | ## インストール |
30 | 21 | ||
31 | ### パッケージから | 22 | ### パッケージから |
@@ -9,11 +9,6 @@ Read the [FAQ](https://github.com/swaywm/sway/wiki). Join the | |||
9 | [IRC channel](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on | 9 | [IRC channel](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on |
10 | irc.freenode.net). | 10 | irc.freenode.net). |
11 | 11 | ||
12 | **Notice**: work is well underway to port sway to | ||
13 | [wlroots](https://github.com/swaywm/wlroots). This is **unstable** and | ||
14 | **unsupported** - we accept patches, but are not fond of bug reports. We are no | ||
15 | longer accepting bugs for 0.15. | ||
16 | |||
17 | If you'd like to support sway development, please contribute to [SirCmpwn's | 12 | If you'd like to support sway development, please contribute to [SirCmpwn's |
18 | Patreon page](https://patreon.com/sircmpwn). | 13 | Patreon page](https://patreon.com/sircmpwn). |
19 | 14 | ||
@@ -22,14 +17,6 @@ Patreon page](https://patreon.com/sircmpwn). | |||
22 | Releases are signed with [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) | 17 | Releases are signed with [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) |
23 | and published [on GitHub](https://github.com/swaywm/sway/releases). | 18 | and published [on GitHub](https://github.com/swaywm/sway/releases). |
24 | 19 | ||
25 | ## Status | ||
26 | |||
27 | - [i3 feature support](https://github.com/swaywm/sway/issues/2) | ||
28 | - [IPC feature support](https://github.com/swaywm/sway/issues/98) | ||
29 | - [i3bar feature support](https://github.com/swaywm/sway/issues/343) | ||
30 | - [i3-gaps feature support](https://github.com/swaywm/sway/issues/307) | ||
31 | - [security features](https://github.com/swaywm/sway/issues/984) | ||
32 | |||
33 | ## Installation | 20 | ## Installation |
34 | 21 | ||
35 | ### From Packages | 22 | ### From Packages |
diff --git a/README.pt.md b/README.pt.md index 9089c8c6..57220fae 100644 --- a/README.pt.md +++ b/README.pt.md | |||
@@ -30,14 +30,6 @@ exite em enviar quaisquer correções necessárias. | |||
30 | [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) | 30 | [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) |
31 | e publicadas [no GitHub](https://github.com/swaywm/sway/releases). | 31 | e publicadas [no GitHub](https://github.com/swaywm/sway/releases). |
32 | 32 | ||
33 | ## Status | ||
34 | |||
35 | - [Suporte aos recursos do i3](https://github.com/swaywm/sway/issues/2) | ||
36 | - [Suporte aos recursos IPC](https://github.com/swaywm/sway/issues/98) | ||
37 | - [Suporte aos recursos do i3bar](https://github.com/swaywm/sway/issues/343) | ||
38 | - [Suporte aos recursos do i3-gaps](https://github.com/swaywm/sway/issues/307) | ||
39 | - [Recursos de segurança](https://github.com/swaywm/sway/issues/984) | ||
40 | |||
41 | ## Instalação | 33 | ## Instalação |
42 | 34 | ||
43 | ### A partir de pacotes | 35 | ### A partir de pacotes |
diff --git a/README.ru.md b/README.ru.md index 68675db3..25b80a23 100644 --- a/README.ru.md +++ b/README.ru.md | |||
@@ -6,8 +6,6 @@ i3-совместимый [Wayland](http://wayland.freedesktop.org/) компо | |||
6 | [IRC каналу](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway на | 6 | [IRC каналу](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway на |
7 | irc.freenode.net). | 7 | irc.freenode.net). |
8 | 8 | ||
9 | **Внимание**: на данный момент ведется активная интеграция wlroots, в связи с чем разработка sway приостановлена, однако патчи продолжают приниматься. | ||
10 | |||
11 | [![](https://sr.ht/ICd5.png)](https://sr.ht/ICd5.png) | 9 | [![](https://sr.ht/ICd5.png)](https://sr.ht/ICd5.png) |
12 | 10 | ||
13 | При желании поддержать разработку Sway вы можете пожертвовать [автору | 11 | При желании поддержать разработку Sway вы можете пожертвовать [автору |
@@ -26,14 +24,6 @@ DarkReef оказывает поддержку на русском языке в | |||
26 | Версии подписаны ключом [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) | 24 | Версии подписаны ключом [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) |
27 | и опубликованы [на GitHub'е](https://github.com/swaywm/sway/releases). | 25 | и опубликованы [на GitHub'е](https://github.com/swaywm/sway/releases). |
28 | 26 | ||
29 | ## Статус | ||
30 | |||
31 | - [Поддержка i3](https://github.com/swaywm/sway/issues/2) | ||
32 | - [Поддержка i3-bar](https://github.com/swaywm/sway/issues/343) | ||
33 | - [Поддержка i3-gaps](https://github.com/swaywm/sway/issues/307) | ||
34 | - [Поддержка IPC](https://github.com/swaywm/sway/issues/98) | ||
35 | - [Безопасность](https://github.com/swaywm/sway/issues/984) | ||
36 | |||
37 | ## Установка | 27 | ## Установка |
38 | 28 | ||
39 | ### Из пакета | 29 | ### Из пакета |
diff --git a/README.uk.md b/README.uk.md index c31a3ea9..8c8b2eed 100644 --- a/README.uk.md +++ b/README.uk.md | |||
@@ -29,14 +29,6 @@ Hummer12007 у IRC-спільноті. Будьте терплячі, вам о | |||
29 | Випуски підписані ключем [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) | 29 | Випуски підписані ключем [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) |
30 | та публікуються на сторінці [GitHub](https://github.com/swaywm/sway/releases). | 30 | та публікуються на сторінці [GitHub](https://github.com/swaywm/sway/releases). |
31 | 31 | ||
32 | ## Стан розробки | ||
33 | |||
34 | - [Підтримка функцій i3](https://github.com/swaywm/sway/issues/2) | ||
35 | - [Реалізація IPC-протоколу i3](https://github.com/swaywm/sway/issues/98) | ||
36 | - [Підтримка функцій i3bar](https://github.com/swaywm/sway/issues/343) | ||
37 | - [Підтримка функцій i3-gaps](https://github.com/swaywm/sway/issues/307) | ||
38 | - [Функції безпеки](https://github.com/swaywm/sway/issues/984) | ||
39 | |||
40 | ## Встановлення | 32 | ## Встановлення |
41 | 33 | ||
42 | ### З пакунків | 34 | ### З пакунків |
diff --git a/common/loop.c b/common/loop.c new file mode 100644 index 00000000..750bee75 --- /dev/null +++ b/common/loop.c | |||
@@ -0,0 +1,180 @@ | |||
1 | #define _POSIX_C_SOURCE 199309L | ||
2 | #include <limits.h> | ||
3 | #include <string.h> | ||
4 | #include <stdbool.h> | ||
5 | #include <stdlib.h> | ||
6 | #include <stdio.h> | ||
7 | #include <poll.h> | ||
8 | #include <time.h> | ||
9 | #include <unistd.h> | ||
10 | #include "list.h" | ||
11 | #include "log.h" | ||
12 | #include "loop.h" | ||
13 | |||
14 | struct loop_fd_event { | ||
15 | void (*callback)(int fd, short mask, void *data); | ||
16 | void *data; | ||
17 | }; | ||
18 | |||
19 | struct loop_timer { | ||
20 | void (*callback)(void *data); | ||
21 | void *data; | ||
22 | struct timespec expiry; | ||
23 | }; | ||
24 | |||
25 | struct loop { | ||
26 | struct pollfd *fds; | ||
27 | int fd_length; | ||
28 | int fd_capacity; | ||
29 | |||
30 | list_t *fd_events; // struct loop_fd_event | ||
31 | list_t *timers; // struct loop_timer | ||
32 | }; | ||
33 | |||
34 | struct loop *loop_create(void) { | ||
35 | struct loop *loop = calloc(1, sizeof(struct loop)); | ||
36 | if (!loop) { | ||
37 | wlr_log(WLR_ERROR, "Unable to allocate memory for loop"); | ||
38 | return NULL; | ||
39 | } | ||
40 | loop->fd_capacity = 10; | ||
41 | loop->fds = malloc(sizeof(struct pollfd) * loop->fd_capacity); | ||
42 | loop->fd_events = create_list(); | ||
43 | loop->timers = create_list(); | ||
44 | return loop; | ||
45 | } | ||
46 | |||
47 | void loop_destroy(struct loop *loop) { | ||
48 | list_foreach(loop->fd_events, free); | ||
49 | list_foreach(loop->timers, free); | ||
50 | list_free(loop->fd_events); | ||
51 | list_free(loop->timers); | ||
52 | free(loop->fds); | ||
53 | free(loop); | ||
54 | } | ||
55 | |||
56 | void loop_poll(struct loop *loop) { | ||
57 | // Calculate next timer in ms | ||
58 | int ms = INT_MAX; | ||
59 | if (loop->timers->length) { | ||
60 | struct timespec now; | ||
61 | clock_gettime(CLOCK_MONOTONIC, &now); | ||
62 | for (int i = 0; i < loop->timers->length; ++i) { | ||
63 | struct loop_timer *timer = loop->timers->items[i]; | ||
64 | int timer_ms = (timer->expiry.tv_sec - now.tv_sec) * 1000; | ||
65 | timer_ms += (timer->expiry.tv_nsec - now.tv_nsec) / 1000000; | ||
66 | if (timer_ms < ms) { | ||
67 | ms = timer_ms; | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | if (ms < 0) { | ||
72 | ms = 0; | ||
73 | } | ||
74 | |||
75 | poll(loop->fds, loop->fd_length, ms); | ||
76 | |||
77 | // Dispatch fds | ||
78 | for (int i = 0; i < loop->fd_length; ++i) { | ||
79 | struct pollfd pfd = loop->fds[i]; | ||
80 | struct loop_fd_event *event = loop->fd_events->items[i]; | ||
81 | |||
82 | // Always send these events | ||
83 | unsigned events = pfd.events | POLLHUP | POLLERR; | ||
84 | |||
85 | if (pfd.revents & events) { | ||
86 | event->callback(pfd.fd, pfd.revents, event->data); | ||
87 | } | ||
88 | } | ||
89 | |||
90 | // Dispatch timers | ||
91 | if (loop->timers->length) { | ||
92 | struct timespec now; | ||
93 | clock_gettime(CLOCK_MONOTONIC, &now); | ||
94 | for (int i = 0; i < loop->timers->length; ++i) { | ||
95 | struct loop_timer *timer = loop->timers->items[i]; | ||
96 | bool expired = timer->expiry.tv_sec < now.tv_sec || | ||
97 | (timer->expiry.tv_sec == now.tv_sec && | ||
98 | timer->expiry.tv_nsec < now.tv_nsec); | ||
99 | if (expired) { | ||
100 | timer->callback(timer->data); | ||
101 | loop_remove_timer(loop, timer); | ||
102 | --i; | ||
103 | } | ||
104 | } | ||
105 | } | ||
106 | } | ||
107 | |||
108 | void loop_add_fd(struct loop *loop, int fd, short mask, | ||
109 | void (*callback)(int fd, short mask, void *data), void *data) { | ||
110 | struct loop_fd_event *event = calloc(1, sizeof(struct loop_fd_event)); | ||
111 | if (!event) { | ||
112 | wlr_log(WLR_ERROR, "Unable to allocate memory for event"); | ||
113 | return; | ||
114 | } | ||
115 | event->callback = callback; | ||
116 | event->data = data; | ||
117 | list_add(loop->fd_events, event); | ||
118 | |||
119 | struct pollfd pfd = {fd, mask, 0}; | ||
120 | |||
121 | if (loop->fd_length == loop->fd_capacity) { | ||
122 | loop->fd_capacity += 10; | ||
123 | loop->fds = realloc(loop->fds, | ||
124 | sizeof(struct pollfd) * loop->fd_capacity); | ||
125 | } | ||
126 | |||
127 | loop->fds[loop->fd_length++] = pfd; | ||
128 | } | ||
129 | |||
130 | struct loop_timer *loop_add_timer(struct loop *loop, int ms, | ||
131 | void (*callback)(void *data), void *data) { | ||
132 | struct loop_timer *timer = calloc(1, sizeof(struct loop_timer)); | ||
133 | if (!timer) { | ||
134 | wlr_log(WLR_ERROR, "Unable to allocate memory for timer"); | ||
135 | return NULL; | ||
136 | } | ||
137 | timer->callback = callback; | ||
138 | timer->data = data; | ||
139 | |||
140 | clock_gettime(CLOCK_MONOTONIC, &timer->expiry); | ||
141 | timer->expiry.tv_sec += ms / 1000; | ||
142 | |||
143 | long int nsec = (ms % 1000) * 1000000; | ||
144 | if (timer->expiry.tv_nsec + nsec >= 1000000000) { | ||
145 | timer->expiry.tv_sec++; | ||
146 | nsec -= 1000000000; | ||
147 | } | ||
148 | timer->expiry.tv_nsec += nsec; | ||
149 | |||
150 | list_add(loop->timers, timer); | ||
151 | |||
152 | return timer; | ||
153 | } | ||
154 | |||
155 | bool loop_remove_fd(struct loop *loop, int fd) { | ||
156 | for (int i = 0; i < loop->fd_length; ++i) { | ||
157 | if (loop->fds[i].fd == fd) { | ||
158 | free(loop->fd_events->items[i]); | ||
159 | list_del(loop->fd_events, i); | ||
160 | |||
161 | loop->fd_length--; | ||
162 | memmove(&loop->fds[i], &loop->fds[i + 1], | ||
163 | sizeof(struct pollfd) * (loop->fd_length - i)); | ||
164 | |||
165 | return true; | ||
166 | } | ||
167 | } | ||
168 | return false; | ||
169 | } | ||
170 | |||
171 | bool loop_remove_timer(struct loop *loop, struct loop_timer *timer) { | ||
172 | for (int i = 0; i < loop->timers->length; ++i) { | ||
173 | if (loop->timers->items[i] == timer) { | ||
174 | list_del(loop->timers, i); | ||
175 | free(timer); | ||
176 | return true; | ||
177 | } | ||
178 | } | ||
179 | return false; | ||
180 | } | ||
diff --git a/common/meson.build b/common/meson.build index 44a29508..224a9c3f 100644 --- a/common/meson.build +++ b/common/meson.build | |||
@@ -5,6 +5,7 @@ lib_sway_common = static_library( | |||
5 | 'cairo.c', | 5 | 'cairo.c', |
6 | 'ipc-client.c', | 6 | 'ipc-client.c', |
7 | 'log.c', | 7 | 'log.c', |
8 | 'loop.c', | ||
8 | 'list.c', | 9 | 'list.c', |
9 | 'pango.c', | 10 | 'pango.c', |
10 | 'readline.c', | 11 | 'readline.c', |
diff --git a/common/pango.c b/common/pango.c index ba74692e..3bc97808 100644 --- a/common/pango.c +++ b/common/pango.c | |||
@@ -10,6 +10,9 @@ | |||
10 | #include "log.h" | 10 | #include "log.h" |
11 | #include "stringop.h" | 11 | #include "stringop.h" |
12 | 12 | ||
13 | static const char overflow[] = "[buffer overflow]"; | ||
14 | static const int max_chars = 16384; | ||
15 | |||
13 | size_t escape_markup_text(const char *src, char *dest) { | 16 | size_t escape_markup_text(const char *src, char *dest) { |
14 | size_t length = 0; | 17 | size_t length = 0; |
15 | if (dest) { | 18 | if (dest) { |
@@ -84,12 +87,12 @@ PangoLayout *get_pango_layout(cairo_t *cairo, const char *font, | |||
84 | 87 | ||
85 | void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, | 88 | void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, |
86 | int *baseline, double scale, bool markup, const char *fmt, ...) { | 89 | int *baseline, double scale, bool markup, const char *fmt, ...) { |
87 | static char buf[2048]; | 90 | char buf[max_chars]; |
88 | 91 | ||
89 | va_list args; | 92 | va_list args; |
90 | va_start(args, fmt); | 93 | va_start(args, fmt); |
91 | if (vsnprintf(buf, 2048, fmt, args) >= 2048) { | 94 | if (vsnprintf(buf, sizeof(buf), fmt, args) >= max_chars) { |
92 | strcpy(buf, "[buffer overflow]"); | 95 | strcpy(&buf[sizeof(buf) - sizeof(overflow)], overflow); |
93 | } | 96 | } |
94 | va_end(args); | 97 | va_end(args); |
95 | 98 | ||
@@ -104,12 +107,12 @@ void get_text_size(cairo_t *cairo, const char *font, int *width, int *height, | |||
104 | 107 | ||
105 | void pango_printf(cairo_t *cairo, const char *font, | 108 | void pango_printf(cairo_t *cairo, const char *font, |
106 | double scale, bool markup, const char *fmt, ...) { | 109 | double scale, bool markup, const char *fmt, ...) { |
107 | static char buf[2048]; | 110 | char buf[max_chars]; |
108 | 111 | ||
109 | va_list args; | 112 | va_list args; |
110 | va_start(args, fmt); | 113 | va_start(args, fmt); |
111 | if (vsnprintf(buf, 2048, fmt, args) >= 2048) { | 114 | if (vsnprintf(buf, sizeof(buf), fmt, args) >= max_chars) { |
112 | strcpy(buf, "[buffer overflow]"); | 115 | strcpy(&buf[sizeof(buf) - sizeof(overflow)], overflow); |
113 | } | 116 | } |
114 | va_end(args); | 117 | va_end(args); |
115 | 118 | ||
diff --git a/include/ipc.h b/include/ipc.h index a3f60e19..9063b933 100644 --- a/include/ipc.h +++ b/include/ipc.h | |||
@@ -30,6 +30,9 @@ enum ipc_command_type { | |||
30 | IPC_EVENT_BINDING = ((1<<31) | 5), | 30 | IPC_EVENT_BINDING = ((1<<31) | 5), |
31 | IPC_EVENT_SHUTDOWN = ((1<<31) | 6), | 31 | IPC_EVENT_SHUTDOWN = ((1<<31) | 6), |
32 | IPC_EVENT_TICK = ((1<<31) | 7), | 32 | IPC_EVENT_TICK = ((1<<31) | 7), |
33 | |||
34 | // sway-specific event types | ||
35 | IPC_EVENT_BAR_STATE_UPDATE = ((1<<31) | 20), | ||
33 | }; | 36 | }; |
34 | 37 | ||
35 | #endif | 38 | #endif |
diff --git a/include/loop.h b/include/loop.h new file mode 100644 index 00000000..2f608eda --- /dev/null +++ b/include/loop.h | |||
@@ -0,0 +1,54 @@ | |||
1 | #ifndef _SWAY_LOOP_H | ||
2 | #define _SWAY_LOOP_H | ||
3 | #include <stdbool.h> | ||
4 | |||
5 | /** | ||
6 | * This is an event loop system designed for sway clients, not sway itself. | ||
7 | * | ||
8 | * The loop consists of file descriptors and timers. Typically the Wayland | ||
9 | * display's file descriptor will be one of the fds in the loop. | ||
10 | */ | ||
11 | |||
12 | struct loop; | ||
13 | struct loop_timer; | ||
14 | |||
15 | /** | ||
16 | * Create an event loop. | ||
17 | */ | ||
18 | struct loop *loop_create(void); | ||
19 | |||
20 | /** | ||
21 | * Destroy the event loop (eg. on program termination). | ||
22 | */ | ||
23 | void loop_destroy(struct loop *loop); | ||
24 | |||
25 | /** | ||
26 | * Poll the event loop. This will block until one of the fds has data. | ||
27 | */ | ||
28 | void loop_poll(struct loop *loop); | ||
29 | |||
30 | /** | ||
31 | * Add a file descriptor to the loop. | ||
32 | */ | ||
33 | void loop_add_fd(struct loop *loop, int fd, short mask, | ||
34 | void (*func)(int fd, short mask, void *data), void *data); | ||
35 | |||
36 | /** | ||
37 | * Add a timer to the loop. | ||
38 | * | ||
39 | * When the timer expires, the timer will be removed from the loop and freed. | ||
40 | */ | ||
41 | struct loop_timer *loop_add_timer(struct loop *loop, int ms, | ||
42 | void (*callback)(void *data), void *data); | ||
43 | |||
44 | /** | ||
45 | * Remove a file descriptor from the loop. | ||
46 | */ | ||
47 | bool loop_remove_fd(struct loop *loop, int fd); | ||
48 | |||
49 | /** | ||
50 | * Remove a timer from the loop. | ||
51 | */ | ||
52 | bool loop_remove_timer(struct loop *loop, struct loop_timer *timer); | ||
53 | |||
54 | #endif | ||
diff --git a/include/sway/config.h b/include/sway/config.h index bc02c0fd..be5a00b5 100644 --- a/include/sway/config.h +++ b/include/sway/config.h | |||
@@ -191,6 +191,7 @@ struct bar_config { | |||
191 | * In "show" mode, it will always be shown on top of the active workspace. | 191 | * In "show" mode, it will always be shown on top of the active workspace. |
192 | */ | 192 | */ |
193 | char *hidden_state; | 193 | char *hidden_state; |
194 | bool visible_by_modifier; // only relevant in "hide" mode | ||
194 | /** | 195 | /** |
195 | * Id name used to identify the bar through IPC. | 196 | * Id name used to identify the bar through IPC. |
196 | * | 197 | * |
@@ -389,7 +390,6 @@ struct sway_config { | |||
389 | bool show_marks; | 390 | bool show_marks; |
390 | bool tiling_drag; | 391 | bool tiling_drag; |
391 | 392 | ||
392 | bool edge_gaps; | ||
393 | bool smart_gaps; | 393 | bool smart_gaps; |
394 | int gaps_inner; | 394 | int gaps_inner; |
395 | int gaps_outer; | 395 | int gaps_outer; |
@@ -531,6 +531,8 @@ void free_sway_binding(struct sway_binding *sb); | |||
531 | 531 | ||
532 | void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding); | 532 | void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding); |
533 | 533 | ||
534 | void load_swaybar(struct bar_config *bar); | ||
535 | |||
534 | void load_swaybars(void); | 536 | void load_swaybars(void); |
535 | 537 | ||
536 | void terminate_swaybg(pid_t pid); | 538 | void terminate_swaybg(pid_t pid); |
diff --git a/include/sway/input/seat.h b/include/sway/input/seat.h index ebb0cd43..be95567e 100644 --- a/include/sway/input/seat.h +++ b/include/sway/input/seat.h | |||
@@ -51,6 +51,7 @@ struct sway_seat { | |||
51 | 51 | ||
52 | bool has_focus; | 52 | bool has_focus; |
53 | struct wl_list focus_stack; // list of containers in focus order | 53 | struct wl_list focus_stack; // list of containers in focus order |
54 | struct sway_workspace *workspace; | ||
54 | 55 | ||
55 | // If the focused layer is set, views cannot receive keyboard focus | 56 | // If the focused layer is set, views cannot receive keyboard focus |
56 | struct wlr_layer_surface_v1 *focused_layer; | 57 | struct wlr_layer_surface_v1 *focused_layer; |
@@ -112,8 +113,16 @@ void seat_set_focus_container(struct sway_seat *seat, | |||
112 | void seat_set_focus_workspace(struct sway_seat *seat, | 113 | void seat_set_focus_workspace(struct sway_seat *seat, |
113 | struct sway_workspace *ws); | 114 | struct sway_workspace *ws); |
114 | 115 | ||
116 | /** | ||
117 | * Manipulate the focus stack without triggering any other behaviour. | ||
118 | * | ||
119 | * This can be used to set focus_inactive by calling the function a second time | ||
120 | * with the real focus. | ||
121 | */ | ||
122 | void seat_set_raw_focus(struct sway_seat *seat, struct sway_node *node); | ||
123 | |||
115 | void seat_set_focus_warp(struct sway_seat *seat, | 124 | void seat_set_focus_warp(struct sway_seat *seat, |
116 | struct sway_node *node, bool warp, bool notify); | 125 | struct sway_node *node, bool warp); |
117 | 126 | ||
118 | void seat_set_focus_surface(struct sway_seat *seat, | 127 | void seat_set_focus_surface(struct sway_seat *seat, |
119 | struct wlr_surface *surface, bool unfocus); | 128 | struct wlr_surface *surface, bool unfocus); |
diff --git a/include/sway/ipc-server.h b/include/sway/ipc-server.h index 80180ec4..3c43f74d 100644 --- a/include/sway/ipc-server.h +++ b/include/sway/ipc-server.h | |||
@@ -15,6 +15,7 @@ void ipc_event_workspace(struct sway_workspace *old, | |||
15 | struct sway_workspace *new, const char *change); | 15 | struct sway_workspace *new, const char *change); |
16 | void ipc_event_window(struct sway_container *window, const char *change); | 16 | void ipc_event_window(struct sway_container *window, const char *change); |
17 | void ipc_event_barconfig_update(struct bar_config *bar); | 17 | void ipc_event_barconfig_update(struct bar_config *bar); |
18 | void ipc_event_bar_state_update(struct bar_config *bar); | ||
18 | void ipc_event_mode(const char *mode, bool pango); | 19 | void ipc_event_mode(const char *mode, bool pango); |
19 | void ipc_event_shutdown(const char *reason); | 20 | void ipc_event_shutdown(const char *reason); |
20 | void ipc_event_binding(struct sway_binding *binding); | 21 | void ipc_event_binding(struct sway_binding *binding); |
diff --git a/include/swaybar/bar.h b/include/swaybar/bar.h index de234111..58e2dee6 100644 --- a/include/swaybar/bar.h +++ b/include/swaybar/bar.h | |||
@@ -8,6 +8,7 @@ | |||
8 | struct swaybar_config; | 8 | struct swaybar_config; |
9 | struct swaybar_output; | 9 | struct swaybar_output; |
10 | struct swaybar_workspace; | 10 | struct swaybar_workspace; |
11 | struct loop; | ||
11 | 12 | ||
12 | struct swaybar_pointer { | 13 | struct swaybar_pointer { |
13 | struct wl_pointer *pointer; | 14 | struct wl_pointer *pointer; |
@@ -37,7 +38,7 @@ enum hotspot_event_handling { | |||
37 | }; | 38 | }; |
38 | 39 | ||
39 | struct swaybar_hotspot { | 40 | struct swaybar_hotspot { |
40 | struct wl_list link; | 41 | struct wl_list link; // swaybar_output::hotspots |
41 | int x, y, width, height; | 42 | int x, y, width, height; |
42 | enum hotspot_event_handling (*callback)(struct swaybar_output *output, | 43 | enum hotspot_event_handling (*callback)(struct swaybar_output *output, |
43 | int x, int y, enum x11_button button, void *data); | 44 | int x, int y, enum x11_button button, void *data); |
@@ -46,6 +47,15 @@ struct swaybar_hotspot { | |||
46 | }; | 47 | }; |
47 | 48 | ||
48 | struct swaybar { | 49 | struct swaybar { |
50 | char *id; | ||
51 | char *mode; | ||
52 | bool mode_pango_markup; | ||
53 | |||
54 | // only relevant when bar is in "hide" mode | ||
55 | bool visible_by_modifier; | ||
56 | bool visible_by_urgency; | ||
57 | bool visible; | ||
58 | |||
49 | struct wl_display *display; | 59 | struct wl_display *display; |
50 | struct wl_compositor *compositor; | 60 | struct wl_compositor *compositor; |
51 | struct zwlr_layer_shell_v1 *layer_shell; | 61 | struct zwlr_layer_shell_v1 *layer_shell; |
@@ -57,14 +67,16 @@ struct swaybar { | |||
57 | struct swaybar_pointer pointer; | 67 | struct swaybar_pointer pointer; |
58 | struct status_line *status; | 68 | struct status_line *status; |
59 | 69 | ||
70 | struct loop *eventloop; | ||
71 | |||
60 | int ipc_event_socketfd; | 72 | int ipc_event_socketfd; |
61 | int ipc_socketfd; | 73 | int ipc_socketfd; |
62 | 74 | ||
63 | struct wl_list outputs; | 75 | struct wl_list outputs; // swaybar_output::link |
64 | }; | 76 | }; |
65 | 77 | ||
66 | struct swaybar_output { | 78 | struct swaybar_output { |
67 | struct wl_list link; | 79 | struct wl_list link; // swaybar::outputs |
68 | struct swaybar *bar; | 80 | struct swaybar *bar; |
69 | struct wl_output *output; | 81 | struct wl_output *output; |
70 | struct zxdg_output_v1 *xdg_output; | 82 | struct zxdg_output_v1 *xdg_output; |
@@ -72,8 +84,8 @@ struct swaybar_output { | |||
72 | struct zwlr_layer_surface_v1 *layer_surface; | 84 | struct zwlr_layer_surface_v1 *layer_surface; |
73 | uint32_t wl_name; | 85 | uint32_t wl_name; |
74 | 86 | ||
75 | struct wl_list workspaces; | 87 | struct wl_list workspaces; // swaybar_workspace::link |
76 | struct wl_list hotspots; | 88 | struct wl_list hotspots; // swaybar_hotspot::link |
77 | 89 | ||
78 | char *name; | 90 | char *name; |
79 | bool focused; | 91 | bool focused; |
@@ -88,7 +100,7 @@ struct swaybar_output { | |||
88 | }; | 100 | }; |
89 | 101 | ||
90 | struct swaybar_workspace { | 102 | struct swaybar_workspace { |
91 | struct wl_list link; | 103 | struct wl_list link; // swaybar_output::workspaces |
92 | int num; | 104 | int num; |
93 | char *name; | 105 | char *name; |
94 | bool focused; | 106 | bool focused; |
@@ -96,10 +108,24 @@ struct swaybar_workspace { | |||
96 | bool urgent; | 108 | bool urgent; |
97 | }; | 109 | }; |
98 | 110 | ||
99 | bool bar_setup(struct swaybar *bar, const char *socket_path, const char *bar_id); | 111 | bool bar_setup(struct swaybar *bar, const char *socket_path); |
100 | void bar_run(struct swaybar *bar); | 112 | void bar_run(struct swaybar *bar); |
101 | void bar_teardown(struct swaybar *bar); | 113 | void bar_teardown(struct swaybar *bar); |
102 | 114 | ||
115 | /* | ||
116 | * Determines whether the bar should be visible and changes it to be so. | ||
117 | * If the current visibility of the bar is the different to what it should be, | ||
118 | * then it adds or destroys the layer surface as required, | ||
119 | * as well as sending the cont or stop signal to the status command. | ||
120 | * If the current visibility of the bar is already what it should be, | ||
121 | * then this function is a no-op, unless moving_layer is true, which occurs | ||
122 | * when the bar changes from "hide" to "dock" mode or vice versa, and the bar | ||
123 | * needs to be destroyed and re-added in order to change its layer. | ||
124 | * | ||
125 | * Returns true if the bar is now visible, otherwise false. | ||
126 | */ | ||
127 | bool determine_bar_visibility(struct swaybar *bar, bool moving_layer); | ||
128 | void free_hotspots(struct wl_list *list); | ||
103 | void free_workspaces(struct wl_list *list); | 129 | void free_workspaces(struct wl_list *list); |
104 | 130 | ||
105 | #endif | 131 | #endif |
diff --git a/include/swaybar/config.h b/include/swaybar/config.h index d0336c27..5d40790a 100644 --- a/include/swaybar/config.h +++ b/include/swaybar/config.h | |||
@@ -13,7 +13,7 @@ struct box_colors { | |||
13 | }; | 13 | }; |
14 | 14 | ||
15 | struct config_output { | 15 | struct config_output { |
16 | struct wl_list link; | 16 | struct wl_list link; // swaybar_config::outputs |
17 | char *name; | 17 | char *name; |
18 | size_t index; | 18 | size_t index; |
19 | }; | 19 | }; |
@@ -31,7 +31,8 @@ struct swaybar_config { | |||
31 | char *font; | 31 | char *font; |
32 | char *sep_symbol; | 32 | char *sep_symbol; |
33 | char *mode; | 33 | char *mode; |
34 | bool mode_pango_markup; | 34 | char *hidden_state; |
35 | char *modifier; | ||
35 | bool strip_workspace_numbers; | 36 | bool strip_workspace_numbers; |
36 | bool binding_mode_indicator; | 37 | bool binding_mode_indicator; |
37 | bool wrap_scroll; | 38 | bool wrap_scroll; |
diff --git a/include/swaybar/event_loop.h b/include/swaybar/event_loop.h deleted file mode 100644 index 47be5b79..00000000 --- a/include/swaybar/event_loop.h +++ /dev/null | |||
@@ -1,26 +0,0 @@ | |||
1 | #ifndef _SWAYBAR_EVENT_LOOP_H | ||
2 | #define _SWAYBAR_EVENT_LOOP_H | ||
3 | #include <stdbool.h> | ||
4 | #include <time.h> | ||
5 | |||
6 | void add_event(int fd, short mask, | ||
7 | void(*cb)(int fd, short mask, void *data), | ||
8 | void *data); | ||
9 | |||
10 | // Not guaranteed to notify cb immediately | ||
11 | void add_timer(timer_t timer, | ||
12 | void(*cb)(timer_t timer, void *data), | ||
13 | void *data); | ||
14 | |||
15 | // Returns false if nothing exists, true otherwise | ||
16 | bool remove_event(int fd); | ||
17 | |||
18 | // Returns false if nothing exists, true otherwise | ||
19 | bool remove_timer(timer_t timer); | ||
20 | |||
21 | // Blocks and returns after sending callbacks | ||
22 | void event_loop_poll(void); | ||
23 | |||
24 | void init_event_loop(void); | ||
25 | |||
26 | #endif | ||
diff --git a/include/swaybar/i3bar.h b/include/swaybar/i3bar.h index 12d9b317..d4a48e07 100644 --- a/include/swaybar/i3bar.h +++ b/include/swaybar/i3bar.h | |||
@@ -5,7 +5,7 @@ | |||
5 | #include "status_line.h" | 5 | #include "status_line.h" |
6 | 6 | ||
7 | struct i3bar_block { | 7 | struct i3bar_block { |
8 | struct wl_list link; | 8 | struct wl_list link; // status_link::blocks |
9 | int ref_count; | 9 | int ref_count; |
10 | char *full_text, *short_text, *align; | 10 | char *full_text, *short_text, *align; |
11 | bool urgent; | 11 | bool urgent; |
diff --git a/include/swaybar/ipc.h b/include/swaybar/ipc.h index 8731dac2..d8cd0c76 100644 --- a/include/swaybar/ipc.h +++ b/include/swaybar/ipc.h | |||
@@ -3,9 +3,9 @@ | |||
3 | #include <stdbool.h> | 3 | #include <stdbool.h> |
4 | #include "swaybar/bar.h" | 4 | #include "swaybar/bar.h" |
5 | 5 | ||
6 | bool ipc_initialize(struct swaybar *bar, const char *bar_id); | 6 | bool ipc_initialize(struct swaybar *bar); |
7 | bool handle_ipc_readable(struct swaybar *bar); | 7 | bool handle_ipc_readable(struct swaybar *bar); |
8 | void ipc_get_workspaces(struct swaybar *bar); | 8 | bool ipc_get_workspaces(struct swaybar *bar); |
9 | void ipc_send_workspace_command(struct swaybar *bar, const char *ws); | 9 | void ipc_send_workspace_command(struct swaybar *bar, const char *ws); |
10 | void ipc_execute_binding(struct swaybar *bar, struct swaybar_binding *bind); | 10 | void ipc_execute_binding(struct swaybar *bar, struct swaybar_binding *bind); |
11 | 11 | ||
diff --git a/include/swaybar/status_line.h b/include/swaybar/status_line.h index ca88b0c5..957a808e 100644 --- a/include/swaybar/status_line.h +++ b/include/swaybar/status_line.h | |||
@@ -14,6 +14,8 @@ enum status_protocol { | |||
14 | }; | 14 | }; |
15 | 15 | ||
16 | struct status_line { | 16 | struct status_line { |
17 | struct swaybar *bar; | ||
18 | |||
17 | pid_t pid; | 19 | pid_t pid; |
18 | int read_fd, write_fd; | 20 | int read_fd, write_fd; |
19 | FILE *read, *write; | 21 | FILE *read, *write; |
@@ -22,6 +24,9 @@ struct status_line { | |||
22 | const char *text; | 24 | const char *text; |
23 | struct wl_list blocks; // i3bar_block::link | 25 | struct wl_list blocks; // i3bar_block::link |
24 | 26 | ||
27 | int stop_signal; | ||
28 | int cont_signal; | ||
29 | |||
25 | bool click_events; | 30 | bool click_events; |
26 | bool clicked; | 31 | bool clicked; |
27 | char *buffer; | 32 | char *buffer; |
diff --git a/include/swaylock/swaylock.h b/include/swaylock/swaylock.h index fbdd42a8..25b41a71 100644 --- a/include/swaylock/swaylock.h +++ b/include/swaylock/swaylock.h | |||
@@ -54,6 +54,10 @@ struct swaylock_password { | |||
54 | }; | 54 | }; |
55 | 55 | ||
56 | struct swaylock_state { | 56 | struct swaylock_state { |
57 | struct loop *eventloop; | ||
58 | struct loop_timer *clear_indicator_timer; // clears the indicator | ||
59 | struct loop_timer *clear_password_timer; // clears the password buffer | ||
60 | struct loop_timer *verify_password_timer; | ||
57 | struct wl_display *display; | 61 | struct wl_display *display; |
58 | struct wl_compositor *compositor; | 62 | struct wl_compositor *compositor; |
59 | struct zwlr_layer_shell_v1 *layer_shell; | 63 | struct zwlr_layer_shell_v1 *layer_shell; |
diff --git a/meson.build b/meson.build index 42386fbc..3fb1e81e 100644 --- a/meson.build +++ b/meson.build | |||
@@ -89,6 +89,7 @@ if scdoc.found() | |||
89 | 'sway/sway.5.scd', | 89 | 'sway/sway.5.scd', |
90 | 'sway/sway-bar.5.scd', | 90 | 'sway/sway-bar.5.scd', |
91 | 'sway/sway-input.5.scd', | 91 | 'sway/sway-input.5.scd', |
92 | 'sway/sway-output.5.scd', | ||
92 | 'swaylock/swaylock.1.scd', | 93 | 'swaylock/swaylock.1.scd', |
93 | 'swaymsg/swaymsg.1.scd', | 94 | 'swaymsg/swaymsg.1.scd', |
94 | 'swayidle/swayidle.1.scd', | 95 | 'swayidle/swayidle.1.scd', |
@@ -113,7 +114,7 @@ if scdoc.found() | |||
113 | endforeach | 114 | endforeach |
114 | endif | 115 | endif |
115 | 116 | ||
116 | add_project_arguments('-DSYSCONFDIR="/@0@/@1@"'.format(prefix, sysconfdir), language : 'c') | 117 | add_project_arguments('-DSYSCONFDIR="/@0@"'.format(sysconfdir), language : 'c') |
117 | 118 | ||
118 | version = get_option('sway-version') | 119 | version = get_option('sway-version') |
119 | if version != '' | 120 | if version != '' |
@@ -156,7 +157,7 @@ subdir('swaynag') | |||
156 | subdir('swaylock') | 157 | subdir('swaylock') |
157 | 158 | ||
158 | config = configuration_data() | 159 | config = configuration_data() |
159 | config.set('sysconfdir', join_paths(prefix, sysconfdir)) | 160 | config.set('sysconfdir', sysconfdir) |
160 | config.set('datadir', join_paths(prefix, datadir)) | 161 | config.set('datadir', join_paths(prefix, datadir)) |
161 | config.set('prefix', prefix) | 162 | config.set('prefix', prefix) |
162 | 163 | ||
diff --git a/sway/commands/bar.c b/sway/commands/bar.c index 03f4c557..c808aef2 100644 --- a/sway/commands/bar.c +++ b/sway/commands/bar.c | |||
@@ -17,7 +17,6 @@ static struct cmd_handler bar_handlers[] = { | |||
17 | { "height", bar_cmd_height }, | 17 | { "height", bar_cmd_height }, |
18 | { "hidden_state", bar_cmd_hidden_state }, | 18 | { "hidden_state", bar_cmd_hidden_state }, |
19 | { "icon_theme", bar_cmd_icon_theme }, | 19 | { "icon_theme", bar_cmd_icon_theme }, |
20 | { "id", bar_cmd_id }, | ||
21 | { "mode", bar_cmd_mode }, | 20 | { "mode", bar_cmd_mode }, |
22 | { "modifier", bar_cmd_modifier }, | 21 | { "modifier", bar_cmd_modifier }, |
23 | { "output", bar_cmd_output }, | 22 | { "output", bar_cmd_output }, |
@@ -27,7 +26,6 @@ static struct cmd_handler bar_handlers[] = { | |||
27 | { "separator_symbol", bar_cmd_separator_symbol }, | 26 | { "separator_symbol", bar_cmd_separator_symbol }, |
28 | { "status_command", bar_cmd_status_command }, | 27 | { "status_command", bar_cmd_status_command }, |
29 | { "strip_workspace_numbers", bar_cmd_strip_workspace_numbers }, | 28 | { "strip_workspace_numbers", bar_cmd_strip_workspace_numbers }, |
30 | { "swaybar_command", bar_cmd_swaybar_command }, | ||
31 | { "tray_output", bar_cmd_tray_output }, | 29 | { "tray_output", bar_cmd_tray_output }, |
32 | { "tray_padding", bar_cmd_tray_padding }, | 30 | { "tray_padding", bar_cmd_tray_padding }, |
33 | { "workspace_buttons", bar_cmd_workspace_buttons }, | 31 | { "workspace_buttons", bar_cmd_workspace_buttons }, |
@@ -36,54 +34,49 @@ static struct cmd_handler bar_handlers[] = { | |||
36 | 34 | ||
37 | // Must be in alphabetical order for bsearch | 35 | // Must be in alphabetical order for bsearch |
38 | static struct cmd_handler bar_config_handlers[] = { | 36 | static struct cmd_handler bar_config_handlers[] = { |
39 | { "hidden_state", bar_cmd_hidden_state }, | 37 | { "id", bar_cmd_id }, |
40 | { "mode", bar_cmd_mode } | 38 | { "swaybar_command", bar_cmd_swaybar_command }, |
41 | }; | 39 | }; |
42 | 40 | ||
41 | // Determines whether the subcommand is valid in any bar handler struct | ||
42 | static bool is_subcommand(char *name) { | ||
43 | return find_handler(name, bar_handlers, sizeof(bar_handlers)) || | ||
44 | find_handler(name, bar_config_handlers, sizeof(bar_config_handlers)); | ||
45 | } | ||
46 | |||
43 | struct cmd_results *cmd_bar(int argc, char **argv) { | 47 | struct cmd_results *cmd_bar(int argc, char **argv) { |
44 | struct cmd_results *error = NULL; | 48 | struct cmd_results *error = NULL; |
45 | if ((error = checkarg(argc, "bar", EXPECTED_AT_LEAST, 1))) { | 49 | if ((error = checkarg(argc, "bar", EXPECTED_AT_LEAST, 2))) { |
46 | return error; | 50 | return error; |
47 | } | 51 | } |
48 | 52 | ||
49 | if (find_handler(argv[0], bar_config_handlers, | 53 | bool spawn = false; |
50 | sizeof(bar_config_handlers))) { | 54 | struct bar_config *bar = NULL; |
51 | if (config->reading) { | 55 | if (strcmp(argv[0], "id") != 0 && is_subcommand(argv[1])) { |
52 | return config_subcommand(argv, argc, bar_config_handlers, | 56 | for (int i = 0; i < config->bars->length; ++i) { |
53 | sizeof(bar_config_handlers)); | 57 | struct bar_config *item = config->bars->items[i]; |
54 | } | 58 | if (strcmp(item->id, argv[0]) == 0) { |
55 | return cmd_results_new(CMD_FAILURE, "bar", | 59 | wlr_log(WLR_DEBUG, "Selecting bar: %s", argv[0]); |
56 | "Can only be used in config file."); | 60 | bar = item; |
57 | } | 61 | break; |
58 | |||
59 | if (argc > 1) { | ||
60 | struct bar_config *bar = NULL; | ||
61 | if (!find_handler(argv[0], bar_handlers, sizeof(bar_handlers)) | ||
62 | && find_handler(argv[1], bar_handlers, sizeof(bar_handlers))) { | ||
63 | for (int i = 0; i < config->bars->length; ++i) { | ||
64 | struct bar_config *item = config->bars->items[i]; | ||
65 | if (strcmp(item->id, argv[0]) == 0) { | ||
66 | wlr_log(WLR_DEBUG, "Selecting bar: %s", argv[0]); | ||
67 | bar = item; | ||
68 | break; | ||
69 | } | ||
70 | } | 62 | } |
63 | } | ||
64 | if (!bar) { | ||
65 | spawn = !config->reading; | ||
66 | wlr_log(WLR_DEBUG, "Creating bar: %s", argv[0]); | ||
67 | bar = default_bar_config(); | ||
71 | if (!bar) { | 68 | if (!bar) { |
72 | wlr_log(WLR_DEBUG, "Creating bar: %s", argv[0]); | 69 | return cmd_results_new(CMD_FAILURE, "bar", |
73 | bar = default_bar_config(); | 70 | "Unable to allocate bar state"); |
74 | if (!bar) { | ||
75 | return cmd_results_new(CMD_FAILURE, "bar", | ||
76 | "Unable to allocate bar state"); | ||
77 | } | ||
78 | |||
79 | bar->id = strdup(argv[0]); | ||
80 | } | 71 | } |
81 | config->current_bar = bar; | 72 | |
82 | ++argv; --argc; | 73 | bar->id = strdup(argv[0]); |
83 | } | 74 | } |
75 | config->current_bar = bar; | ||
76 | ++argv; --argc; | ||
84 | } | 77 | } |
85 | 78 | ||
86 | if (!config->current_bar) { | 79 | if (!config->current_bar && config->reading) { |
87 | // Create new bar with default values | 80 | // Create new bar with default values |
88 | struct bar_config *bar = default_bar_config(); | 81 | struct bar_config *bar = default_bar_config(); |
89 | if (!bar) { | 82 | if (!bar) { |
@@ -92,18 +85,13 @@ struct cmd_results *cmd_bar(int argc, char **argv) { | |||
92 | } | 85 | } |
93 | 86 | ||
94 | // set bar id | 87 | // set bar id |
95 | for (int i = 0; i < config->bars->length; ++i) { | 88 | const int len = 5 + numlen(config->bars->length - 1); // "bar-"+i+\0 |
96 | if (bar == config->bars->items[i]) { | 89 | bar->id = malloc(len * sizeof(char)); |
97 | const int len = 5 + numlen(i); // "bar-" + i + \0 | 90 | if (bar->id) { |
98 | bar->id = malloc(len * sizeof(char)); | 91 | snprintf(bar->id, len, "bar-%d", config->bars->length - 1); |
99 | if (bar->id) { | 92 | } else { |
100 | snprintf(bar->id, len, "bar-%d", i); | 93 | return cmd_results_new(CMD_FAILURE, |
101 | } else { | 94 | "bar", "Unable to allocate bar ID"); |
102 | return cmd_results_new(CMD_FAILURE, | ||
103 | "bar", "Unable to allocate bar ID"); | ||
104 | } | ||
105 | break; | ||
106 | } | ||
107 | } | 95 | } |
108 | 96 | ||
109 | // Set current bar | 97 | // Set current bar |
@@ -111,5 +99,32 @@ struct cmd_results *cmd_bar(int argc, char **argv) { | |||
111 | wlr_log(WLR_DEBUG, "Creating bar %s", bar->id); | 99 | wlr_log(WLR_DEBUG, "Creating bar %s", bar->id); |
112 | } | 100 | } |
113 | 101 | ||
114 | return config_subcommand(argv, argc, bar_handlers, sizeof(bar_handlers)); | 102 | if (find_handler(argv[0], bar_config_handlers, |
103 | sizeof(bar_config_handlers))) { | ||
104 | if (config->reading) { | ||
105 | return config_subcommand(argv, argc, bar_config_handlers, | ||
106 | sizeof(bar_config_handlers)); | ||
107 | } else if (spawn) { | ||
108 | for (int i = config->bars->length - 1; i >= 0; i--) { | ||
109 | struct bar_config *bar = config->bars->items[i]; | ||
110 | if (bar == config->current_bar) { | ||
111 | list_del(config->bars, i); | ||
112 | free_bar_config(bar); | ||
113 | break; | ||
114 | } | ||
115 | } | ||
116 | } | ||
117 | return cmd_results_new(CMD_INVALID, "bar", | ||
118 | "Can only be used in the config file."); | ||
119 | } | ||
120 | |||
121 | struct cmd_results *res = | ||
122 | config_subcommand(argv, argc, bar_handlers, sizeof(bar_handlers)); | ||
123 | if (!config->reading) { | ||
124 | if (spawn) { | ||
125 | load_swaybar(config->current_bar); | ||
126 | } | ||
127 | config->current_bar = NULL; | ||
128 | } | ||
129 | return res; | ||
115 | } | 130 | } |
diff --git a/sway/commands/bar/hidden_state.c b/sway/commands/bar/hidden_state.c index 502ce2c4..28adf6c7 100644 --- a/sway/commands/bar/hidden_state.c +++ b/sway/commands/bar/hidden_state.c | |||
@@ -32,7 +32,7 @@ static struct cmd_results *bar_set_hidden_state(struct bar_config *bar, | |||
32 | } | 32 | } |
33 | // free old mode | 33 | // free old mode |
34 | free(old_state); | 34 | free(old_state); |
35 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 35 | return NULL; |
36 | } | 36 | } |
37 | 37 | ||
38 | struct cmd_results *bar_cmd_hidden_state(int argc, char **argv) { | 38 | struct cmd_results *bar_cmd_hidden_state(int argc, char **argv) { |
@@ -50,24 +50,20 @@ struct cmd_results *bar_cmd_hidden_state(int argc, char **argv) { | |||
50 | 50 | ||
51 | const char *state = argv[0]; | 51 | const char *state = argv[0]; |
52 | if (config->reading) { | 52 | if (config->reading) { |
53 | return bar_set_hidden_state(config->current_bar, state); | 53 | error = bar_set_hidden_state(config->current_bar, state); |
54 | } | 54 | } else { |
55 | 55 | const char *id = argc == 2 ? argv[1] : NULL; | |
56 | const char *id = NULL; | 56 | for (int i = 0; i < config->bars->length; ++i) { |
57 | if (argc == 2) { | 57 | struct bar_config *bar = config->bars->items[i]; |
58 | id = argv[1]; | 58 | if (id) { |
59 | } | 59 | if (strcmp(id, bar->id) == 0) { |
60 | struct bar_config *bar; | 60 | error = bar_set_hidden_state(bar, state); |
61 | for (int i = 0; i < config->bars->length; ++i) { | 61 | break; |
62 | bar = config->bars->items[i]; | 62 | } |
63 | if (id && strcmp(id, bar->id) == 0) { | 63 | } else if ((error = bar_set_hidden_state(bar, state))) { |
64 | return bar_set_hidden_state(bar, state); | 64 | break; |
65 | } | 65 | } |
66 | |||
67 | error = bar_set_hidden_state(bar, state); | ||
68 | if (error) { | ||
69 | return error; | ||
70 | } | 66 | } |
71 | } | 67 | } |
72 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 68 | return error ? error : cmd_results_new(CMD_SUCCESS, NULL, NULL); |
73 | } | 69 | } |
diff --git a/sway/commands/bar/id.c b/sway/commands/bar/id.c index 65fa69fd..7690a852 100644 --- a/sway/commands/bar/id.c +++ b/sway/commands/bar/id.c | |||
@@ -13,6 +13,8 @@ struct cmd_results *bar_cmd_id(int argc, char **argv) { | |||
13 | const char *oldname = config->current_bar->id; | 13 | const char *oldname = config->current_bar->id; |
14 | if (strcmp(name, oldname) == 0) { | 14 | if (strcmp(name, oldname) == 0) { |
15 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); // NOP | 15 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); // NOP |
16 | } else if (strcmp(name, "id") == 0) { | ||
17 | return cmd_results_new(CMD_INVALID, "id", "id cannot be 'id'"); | ||
16 | } | 18 | } |
17 | // check if id is used by a previously defined bar | 19 | // check if id is used by a previously defined bar |
18 | for (int i = 0; i < config->bars->length; ++i) { | 20 | for (int i = 0; i < config->bars->length; ++i) { |
diff --git a/sway/commands/bar/mode.c b/sway/commands/bar/mode.c index 28e2d77b..dbdd3897 100644 --- a/sway/commands/bar/mode.c +++ b/sway/commands/bar/mode.c | |||
@@ -33,7 +33,7 @@ static struct cmd_results *bar_set_mode(struct bar_config *bar, const char *mode | |||
33 | 33 | ||
34 | // free old mode | 34 | // free old mode |
35 | free(old_mode); | 35 | free(old_mode); |
36 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 36 | return NULL; |
37 | } | 37 | } |
38 | 38 | ||
39 | struct cmd_results *bar_cmd_mode(int argc, char **argv) { | 39 | struct cmd_results *bar_cmd_mode(int argc, char **argv) { |
@@ -51,24 +51,20 @@ struct cmd_results *bar_cmd_mode(int argc, char **argv) { | |||
51 | 51 | ||
52 | const char *mode = argv[0]; | 52 | const char *mode = argv[0]; |
53 | if (config->reading) { | 53 | if (config->reading) { |
54 | return bar_set_mode(config->current_bar, mode); | 54 | error = bar_set_mode(config->current_bar, mode); |
55 | } | 55 | } else { |
56 | 56 | const char *id = argc == 2 ? argv[1] : NULL; | |
57 | const char *id = NULL; | 57 | for (int i = 0; i < config->bars->length; ++i) { |
58 | if (argc == 2) { | 58 | struct bar_config *bar = config->bars->items[i]; |
59 | id = argv[1]; | 59 | if (id) { |
60 | } | 60 | if (strcmp(id, bar->id) == 0) { |
61 | 61 | error = bar_set_mode(bar, mode); | |
62 | struct bar_config *bar; | 62 | break; |
63 | for (int i = 0; i < config->bars->length; ++i) { | 63 | } |
64 | bar = config->bars->items[i]; | 64 | } else if ((error = bar_set_mode(bar, mode))) { |
65 | if (id && strcmp(id, bar->id) == 0) { | 65 | break; |
66 | return bar_set_mode(bar, mode); | 66 | } |
67 | } | ||
68 | error = bar_set_mode(bar, mode); | ||
69 | if (error) { | ||
70 | return error; | ||
71 | } | 67 | } |
72 | } | 68 | } |
73 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 69 | return error ? error : cmd_results_new(CMD_SUCCESS, NULL, NULL); |
74 | } | 70 | } |
diff --git a/sway/commands/bar/status_command.c b/sway/commands/bar/status_command.c index 5b4fdc87..490393f1 100644 --- a/sway/commands/bar/status_command.c +++ b/sway/commands/bar/status_command.c | |||
@@ -25,7 +25,7 @@ struct cmd_results *bar_cmd_status_command(int argc, char **argv) { | |||
25 | } | 25 | } |
26 | 26 | ||
27 | if (config->active && !config->validating) { | 27 | if (config->active && !config->validating) { |
28 | load_swaybars(); | 28 | load_swaybar(config->current_bar); |
29 | } | 29 | } |
30 | 30 | ||
31 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 31 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
diff --git a/sway/commands/border.c b/sway/commands/border.c index bfd3b9ed..cc0d635a 100644 --- a/sway/commands/border.c +++ b/sway/commands/border.c | |||
@@ -81,7 +81,7 @@ struct cmd_results *cmd_border(int argc, char **argv) { | |||
81 | border_toggle(view); | 81 | border_toggle(view); |
82 | } else { | 82 | } else { |
83 | return cmd_results_new(CMD_INVALID, "border", | 83 | return cmd_results_new(CMD_INVALID, "border", |
84 | "Expected 'border <none|normal|pixel|toggle>' " | 84 | "Expected 'border <none|normal|pixel|csd|toggle>' " |
85 | "or 'border pixel <px>'"); | 85 | "or 'border pixel <px>'"); |
86 | } | 86 | } |
87 | if (argc == 2) { | 87 | if (argc == 2) { |
diff --git a/sway/commands/gaps.c b/sway/commands/gaps.c index 2e0876a9..042b415f 100644 --- a/sway/commands/gaps.c +++ b/sway/commands/gaps.c | |||
@@ -20,31 +20,6 @@ struct gaps_data { | |||
20 | int amount; | 20 | int amount; |
21 | }; | 21 | }; |
22 | 22 | ||
23 | // gaps edge_gaps on|off|toggle | ||
24 | static struct cmd_results *gaps_edge_gaps(int argc, char **argv) { | ||
25 | struct cmd_results *error; | ||
26 | if ((error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 2))) { | ||
27 | return error; | ||
28 | } | ||
29 | |||
30 | if (strcmp(argv[1], "on") == 0) { | ||
31 | config->edge_gaps = true; | ||
32 | } else if (strcmp(argv[1], "off") == 0) { | ||
33 | config->edge_gaps = false; | ||
34 | } else if (strcmp(argv[1], "toggle") == 0) { | ||
35 | if (!config->active) { | ||
36 | return cmd_results_new(CMD_INVALID, "gaps", | ||
37 | "Cannot toggle gaps while not running."); | ||
38 | } | ||
39 | config->edge_gaps = !config->edge_gaps; | ||
40 | } else { | ||
41 | return cmd_results_new(CMD_INVALID, "gaps", | ||
42 | "gaps edge_gaps on|off|toggle"); | ||
43 | } | ||
44 | arrange_root(); | ||
45 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | ||
46 | } | ||
47 | |||
48 | // gaps inner|outer <px> | 23 | // gaps inner|outer <px> |
49 | static struct cmd_results *gaps_set_defaults(int argc, char **argv) { | 24 | static struct cmd_results *gaps_set_defaults(int argc, char **argv) { |
50 | struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 2); | 25 | struct cmd_results *error = checkarg(argc, "gaps", EXPECTED_EQUAL_TO, 2); |
@@ -68,15 +43,17 @@ static struct cmd_results *gaps_set_defaults(int argc, char **argv) { | |||
68 | return cmd_results_new(CMD_INVALID, "gaps", | 43 | return cmd_results_new(CMD_INVALID, "gaps", |
69 | "Expected 'gaps inner|outer <px>'"); | 44 | "Expected 'gaps inner|outer <px>'"); |
70 | } | 45 | } |
71 | if (amount < 0) { | ||
72 | amount = 0; | ||
73 | } | ||
74 | |||
75 | if (inner) { | 46 | if (inner) { |
76 | config->gaps_inner = amount; | 47 | config->gaps_inner = (amount >= 0) ? amount : 0; |
77 | } else { | 48 | } else { |
78 | config->gaps_outer = amount; | 49 | config->gaps_outer = amount; |
79 | } | 50 | } |
51 | |||
52 | // Prevent negative outer gaps from moving windows out of the workspace. | ||
53 | if (config->gaps_outer < -config->gaps_inner) { | ||
54 | config->gaps_outer = -config->gaps_inner; | ||
55 | } | ||
56 | |||
80 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 57 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
81 | } | 58 | } |
82 | 59 | ||
@@ -95,8 +72,12 @@ static void configure_gaps(struct sway_workspace *ws, void *_data) { | |||
95 | *prop -= data->amount; | 72 | *prop -= data->amount; |
96 | break; | 73 | break; |
97 | } | 74 | } |
98 | if (*prop < 0) { | 75 | // Prevent invalid gaps configurations. |
99 | *prop = 0; | 76 | if (ws->gaps_inner < 0) { |
77 | ws->gaps_inner = 0; | ||
78 | } | ||
79 | if (ws->gaps_outer < -ws->gaps_inner) { | ||
80 | ws->gaps_outer = -ws->gaps_inner; | ||
100 | } | 81 | } |
101 | arrange_workspace(ws); | 82 | arrange_workspace(ws); |
102 | } | 83 | } |
@@ -156,7 +137,6 @@ static struct cmd_results *gaps_set_runtime(int argc, char **argv) { | |||
156 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); | 137 | return cmd_results_new(CMD_SUCCESS, NULL, NULL); |
157 | } | 138 | } |
158 | 139 | ||
159 | // gaps edge_gaps on|off|toggle | ||
160 | // gaps inner|outer <px> - sets defaults for workspaces | 140 | // gaps inner|outer <px> - sets defaults for workspaces |
161 | // gaps inner|outer current|all set|plus|minus <px> - runtime only | 141 | // gaps inner|outer current|all set|plus|minus <px> - runtime only |
162 | struct cmd_results *cmd_gaps(int argc, char **argv) { | 142 | struct cmd_results *cmd_gaps(int argc, char **argv) { |
@@ -165,10 +145,6 @@ struct cmd_results *cmd_gaps(int argc, char **argv) { | |||
165 | return error; | 145 | return error; |
166 | } | 146 | } |
167 | 147 | ||
168 | if (strcmp(argv[0], "edge_gaps") == 0) { | ||
169 | return gaps_edge_gaps(argc, argv); | ||
170 | } | ||
171 | |||
172 | if (argc == 2) { | 148 | if (argc == 2) { |
173 | return gaps_set_defaults(argc, argv); | 149 | return gaps_set_defaults(argc, argv); |
174 | } | 150 | } |
diff --git a/sway/commands/move.c b/sway/commands/move.c index fc2f1cc1..24036f36 100644 --- a/sway/commands/move.c +++ b/sway/commands/move.c | |||
@@ -543,7 +543,7 @@ static struct cmd_results *cmd_move_container(int argc, char **argv) { | |||
543 | if (new_output_last_ws && new_output_last_ws != new_workspace) { | 543 | if (new_output_last_ws && new_output_last_ws != new_workspace) { |
544 | struct sway_node *new_output_last_focus = | 544 | struct sway_node *new_output_last_focus = |
545 | seat_get_focus_inactive(seat, &new_output_last_ws->node); | 545 | seat_get_focus_inactive(seat, &new_output_last_ws->node); |
546 | seat_set_focus_warp(seat, new_output_last_focus, false, false); | 546 | seat_set_raw_focus(seat, new_output_last_focus); |
547 | } | 547 | } |
548 | 548 | ||
549 | // restore focus | 549 | // restore focus |
@@ -556,7 +556,7 @@ static struct cmd_results *cmd_move_container(int argc, char **argv) { | |||
556 | focus = seat_get_focus_inactive(seat, &old_ws->node); | 556 | focus = seat_get_focus_inactive(seat, &old_ws->node); |
557 | } | 557 | } |
558 | } | 558 | } |
559 | seat_set_focus_warp(seat, focus, true, false); | 559 | seat_set_focus(seat, focus); |
560 | 560 | ||
561 | // clean-up, destroying parents if the container was the last child | 561 | // clean-up, destroying parents if the container was the last child |
562 | if (old_parent) { | 562 | if (old_parent) { |
@@ -593,7 +593,7 @@ static void workspace_move_to_output(struct sway_workspace *workspace, | |||
593 | char *ws_name = workspace_next_name(old_output->wlr_output->name); | 593 | char *ws_name = workspace_next_name(old_output->wlr_output->name); |
594 | struct sway_workspace *ws = workspace_create(old_output, ws_name); | 594 | struct sway_workspace *ws = workspace_create(old_output, ws_name); |
595 | free(ws_name); | 595 | free(ws_name); |
596 | seat_set_focus_workspace(seat, ws); | 596 | seat_set_raw_focus(seat, &ws->node); |
597 | } | 597 | } |
598 | 598 | ||
599 | workspace_consider_destroy(new_output_old_ws); | 599 | workspace_consider_destroy(new_output_old_ws); |
@@ -704,7 +704,7 @@ static struct cmd_results *cmd_move_in_direction( | |||
704 | } | 704 | } |
705 | 705 | ||
706 | // Hack to re-focus container | 706 | // Hack to re-focus container |
707 | seat_set_focus_workspace(config->handler_context.seat, new_ws); | 707 | seat_set_raw_focus(config->handler_context.seat, &new_ws->node); |
708 | seat_set_focus_container(config->handler_context.seat, container); | 708 | seat_set_focus_container(config->handler_context.seat, container); |
709 | 709 | ||
710 | if (old_ws != new_ws) { | 710 | if (old_ws != new_ws) { |
diff --git a/sway/commands/sticky.c b/sway/commands/sticky.c index 7995cdd6..f18322b7 100644 --- a/sway/commands/sticky.c +++ b/sway/commands/sticky.c | |||
@@ -16,6 +16,11 @@ struct cmd_results *cmd_sticky(int argc, char **argv) { | |||
16 | return error; | 16 | return error; |
17 | } | 17 | } |
18 | struct sway_container *container = config->handler_context.container; | 18 | struct sway_container *container = config->handler_context.container; |
19 | |||
20 | if (container == NULL) { | ||
21 | return cmd_results_new(CMD_FAILURE, "sticky", "No current container"); | ||
22 | }; | ||
23 | |||
19 | if (!container_is_floating(container)) { | 24 | if (!container_is_floating(container)) { |
20 | return cmd_results_new(CMD_FAILURE, "sticky", | 25 | return cmd_results_new(CMD_FAILURE, "sticky", |
21 | "Can't set sticky on a tiled container"); | 26 | "Can't set sticky on a tiled container"); |
diff --git a/sway/commands/swap.c b/sway/commands/swap.c index e7f9cbea..9cc0d5c2 100644 --- a/sway/commands/swap.c +++ b/sway/commands/swap.c | |||
@@ -22,6 +22,7 @@ static void swap_places(struct sway_container *con1, | |||
22 | temp->width = con1->width; | 22 | temp->width = con1->width; |
23 | temp->height = con1->height; | 23 | temp->height = con1->height; |
24 | temp->parent = con1->parent; | 24 | temp->parent = con1->parent; |
25 | temp->workspace = con1->workspace; | ||
25 | 26 | ||
26 | con1->x = con2->x; | 27 | con1->x = con2->x; |
27 | con1->y = con2->y; | 28 | con1->y = con2->y; |
@@ -34,8 +35,18 @@ static void swap_places(struct sway_container *con1, | |||
34 | con2->height = temp->height; | 35 | con2->height = temp->height; |
35 | 36 | ||
36 | int temp_index = container_sibling_index(con1); | 37 | int temp_index = container_sibling_index(con1); |
37 | container_insert_child(con2->parent, con1, container_sibling_index(con2)); | 38 | if (con2->parent) { |
38 | container_insert_child(temp->parent, con2, temp_index); | 39 | container_insert_child(con2->parent, con1, |
40 | container_sibling_index(con2)); | ||
41 | } else { | ||
42 | workspace_insert_tiling(con2->workspace, con1, | ||
43 | container_sibling_index(con2)); | ||
44 | } | ||
45 | if (temp->parent) { | ||
46 | container_insert_child(temp->parent, con2, temp_index); | ||
47 | } else { | ||
48 | workspace_insert_tiling(temp->workspace, con2, temp_index); | ||
49 | } | ||
39 | 50 | ||
40 | free(temp); | 51 | free(temp); |
41 | } | 52 | } |
@@ -50,13 +61,13 @@ static void swap_focus(struct sway_container *con1, | |||
50 | enum sway_container_layout layout2 = container_parent_layout(con2); | 61 | enum sway_container_layout layout2 = container_parent_layout(con2); |
51 | if (focus == con1 && (layout2 == L_TABBED || layout2 == L_STACKED)) { | 62 | if (focus == con1 && (layout2 == L_TABBED || layout2 == L_STACKED)) { |
52 | if (workspace_is_visible(ws2)) { | 63 | if (workspace_is_visible(ws2)) { |
53 | seat_set_focus_warp(seat, &con2->node, false, true); | 64 | seat_set_focus_warp(seat, &con2->node, false); |
54 | } | 65 | } |
55 | seat_set_focus_container(seat, ws1 != ws2 ? con2 : con1); | 66 | seat_set_focus_container(seat, ws1 != ws2 ? con2 : con1); |
56 | } else if (focus == con2 && (layout1 == L_TABBED | 67 | } else if (focus == con2 && (layout1 == L_TABBED |
57 | || layout1 == L_STACKED)) { | 68 | || layout1 == L_STACKED)) { |
58 | if (workspace_is_visible(ws1)) { | 69 | if (workspace_is_visible(ws1)) { |
59 | seat_set_focus_warp(seat, &con1->node, false, true); | 70 | seat_set_focus_warp(seat, &con1->node, false); |
60 | } | 71 | } |
61 | seat_set_focus_container(seat, ws1 != ws2 ? con1 : con2); | 72 | seat_set_focus_container(seat, ws1 != ws2 ? con1 : con2); |
62 | } else if (ws1 != ws2) { | 73 | } else if (ws1 != ws2) { |
diff --git a/sway/commands/workspace.c b/sway/commands/workspace.c index 63f29641..58c2201d 100644 --- a/sway/commands/workspace.c +++ b/sway/commands/workspace.c | |||
@@ -1,5 +1,6 @@ | |||
1 | #define _XOPEN_SOURCE 500 | 1 | #define _XOPEN_SOURCE 500 |
2 | #include <ctype.h> | 2 | #include <ctype.h> |
3 | #include <limits.h> | ||
3 | #include <string.h> | 4 | #include <string.h> |
4 | #include <strings.h> | 5 | #include <strings.h> |
5 | #include "sway/commands.h" | 6 | #include "sway/commands.h" |
@@ -20,8 +21,8 @@ static struct workspace_config *workspace_config_find_or_create(char *ws_name) { | |||
20 | return NULL; | 21 | return NULL; |
21 | } | 22 | } |
22 | wsc->workspace = strdup(ws_name); | 23 | wsc->workspace = strdup(ws_name); |
23 | wsc->gaps_inner = -1; | 24 | wsc->gaps_inner = INT_MIN; |
24 | wsc->gaps_outer = -1; | 25 | wsc->gaps_outer = INT_MIN; |
25 | list_add(config->workspace_configs, wsc); | 26 | list_add(config->workspace_configs, wsc); |
26 | return wsc; | 27 | return wsc; |
27 | } | 28 | } |
@@ -94,7 +95,16 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { | |||
94 | return cmd_results_new(CMD_FAILURE, "workspace gaps", | 95 | return cmd_results_new(CMD_FAILURE, "workspace gaps", |
95 | "Expected 'workspace <ws> gaps inner|outer <px>'"); | 96 | "Expected 'workspace <ws> gaps inner|outer <px>'"); |
96 | } | 97 | } |
97 | *prop = val >= 0 ? val : 0; | 98 | *prop = val; |
99 | |||
100 | // Prevent invalid gaps configurations. | ||
101 | if (wsc->gaps_inner < 0) { | ||
102 | wsc->gaps_inner = 0; | ||
103 | } | ||
104 | if (wsc->gaps_outer < -wsc->gaps_inner) { | ||
105 | wsc->gaps_outer = -wsc->gaps_inner; | ||
106 | } | ||
107 | |||
98 | } else { | 108 | } else { |
99 | if (config->reading || !config->active) { | 109 | if (config->reading || !config->active) { |
100 | return cmd_results_new(CMD_DEFER, "workspace", NULL); | 110 | return cmd_results_new(CMD_DEFER, "workspace", NULL); |
@@ -132,7 +142,11 @@ struct cmd_results *cmd_workspace(int argc, char **argv) { | |||
132 | strcasecmp(argv[0], "current") == 0) { | 142 | strcasecmp(argv[0], "current") == 0) { |
133 | ws = workspace_by_name(argv[0]); | 143 | ws = workspace_by_name(argv[0]); |
134 | } else if (strcasecmp(argv[0], "back_and_forth") == 0) { | 144 | } else if (strcasecmp(argv[0], "back_and_forth") == 0) { |
135 | if (!(ws = workspace_by_name(argv[0])) && prev_workspace_name) { | 145 | if (!prev_workspace_name) { |
146 | return cmd_results_new(CMD_INVALID, "workspace", | ||
147 | "There is no previous workspace"); | ||
148 | } | ||
149 | if (!(ws = workspace_by_name(argv[0]))) { | ||
136 | ws = workspace_create(NULL, prev_workspace_name); | 150 | ws = workspace_create(NULL, prev_workspace_name); |
137 | } | 151 | } |
138 | } else { | 152 | } else { |
diff --git a/sway/config.c b/sway/config.c index f239ba1d..89b89464 100644 --- a/sway/config.c +++ b/sway/config.c | |||
@@ -234,7 +234,6 @@ static void config_defaults(struct sway_config *config) { | |||
234 | config->show_marks = true; | 234 | config->show_marks = true; |
235 | config->tiling_drag = true; | 235 | config->tiling_drag = true; |
236 | 236 | ||
237 | config->edge_gaps = true; | ||
238 | config->smart_gaps = false; | 237 | config->smart_gaps = false; |
239 | config->gaps_inner = 0; | 238 | config->gaps_inner = 0; |
240 | config->gaps_outer = 0; | 239 | config->gaps_outer = 0; |
diff --git a/sway/config/bar.c b/sway/config/bar.c index c6899f57..8b88642e 100644 --- a/sway/config/bar.c +++ b/sway/config/bar.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include "stringop.h" | 16 | #include "stringop.h" |
17 | #include "list.h" | 17 | #include "list.h" |
18 | #include "log.h" | 18 | #include "log.h" |
19 | #include "util.h" | ||
19 | 20 | ||
20 | static void terminate_swaybar(pid_t pid) { | 21 | static void terminate_swaybar(pid_t pid) { |
21 | wlr_log(WLR_DEBUG, "Terminating swaybar %d", pid); | 22 | wlr_log(WLR_DEBUG, "Terminating swaybar %d", pid); |
@@ -101,6 +102,7 @@ struct bar_config *default_bar_config(void) { | |||
101 | bar->binding_mode_indicator = true; | 102 | bar->binding_mode_indicator = true; |
102 | bar->verbose = false; | 103 | bar->verbose = false; |
103 | bar->pid = 0; | 104 | bar->pid = 0; |
105 | bar->modifier = get_modifier_mask_by_name("Mod4"); | ||
104 | if (!(bar->mode = strdup("dock"))) { | 106 | if (!(bar->mode = strdup("dock"))) { |
105 | goto cleanup; | 107 | goto cleanup; |
106 | } | 108 | } |
@@ -226,13 +228,17 @@ static void invoke_swaybar(struct bar_config *bar) { | |||
226 | close(filedes[1]); | 228 | close(filedes[1]); |
227 | } | 229 | } |
228 | 230 | ||
231 | void load_swaybar(struct bar_config *bar) { | ||
232 | if (bar->pid != 0) { | ||
233 | terminate_swaybar(bar->pid); | ||
234 | } | ||
235 | wlr_log(WLR_DEBUG, "Invoking swaybar for bar id '%s'", bar->id); | ||
236 | invoke_swaybar(bar); | ||
237 | } | ||
238 | |||
229 | void load_swaybars(void) { | 239 | void load_swaybars(void) { |
230 | for (int i = 0; i < config->bars->length; ++i) { | 240 | for (int i = 0; i < config->bars->length; ++i) { |
231 | struct bar_config *bar = config->bars->items[i]; | 241 | struct bar_config *bar = config->bars->items[i]; |
232 | if (bar->pid != 0) { | 242 | load_swaybar(bar); |
233 | terminate_swaybar(bar->pid); | ||
234 | } | ||
235 | wlr_log(WLR_DEBUG, "Invoking swaybar for bar id '%s'", bar->id); | ||
236 | invoke_swaybar(bar); | ||
237 | } | 243 | } |
238 | } | 244 | } |
diff --git a/sway/desktop/output.c b/sway/desktop/output.c index adc1ee10..fc52dd28 100644 --- a/sway/desktop/output.c +++ b/sway/desktop/output.c | |||
@@ -223,11 +223,15 @@ void output_drag_icons_for_each_surface(struct sway_output *output, | |||
223 | } | 223 | } |
224 | } | 224 | } |
225 | 225 | ||
226 | static int scale_length(int length, int offset, float scale) { | ||
227 | return round((offset + length) * scale) - round(offset * scale); | ||
228 | } | ||
229 | |||
226 | static void scale_box(struct wlr_box *box, float scale) { | 230 | static void scale_box(struct wlr_box *box, float scale) { |
227 | box->x *= scale; | 231 | box->width = scale_length(box->width, box->x, scale); |
228 | box->y *= scale; | 232 | box->height = scale_length(box->height, box->y, scale); |
229 | box->width *= scale; | 233 | box->x = round(box->x * scale); |
230 | box->height *= scale; | 234 | box->y = round(box->y * scale); |
231 | } | 235 | } |
232 | 236 | ||
233 | struct sway_workspace *output_get_active_workspace(struct sway_output *output) { | 237 | struct sway_workspace *output_get_active_workspace(struct sway_output *output) { |
diff --git a/sway/desktop/render.c b/sway/desktop/render.c index 3617da87..9b26c560 100644 --- a/sway/desktop/render.c +++ b/sway/desktop/render.c | |||
@@ -33,11 +33,27 @@ struct render_data { | |||
33 | float alpha; | 33 | float alpha; |
34 | }; | 34 | }; |
35 | 35 | ||
36 | /** | ||
37 | * Apply scale to a width or height. | ||
38 | * | ||
39 | * One does not simply multiply the width by the scale. We allow fractional | ||
40 | * scaling, which means the resulting scaled width might be a decimal. | ||
41 | * So we round it. | ||
42 | * | ||
43 | * But even this can produce undesirable results depending on the X or Y offset | ||
44 | * of the box. For example, with a scale of 1.5, a box with width=1 should not | ||
45 | * scale to 2px if its X coordinate is 1, because the X coordinate would have | ||
46 | * scaled to 2px. | ||
47 | */ | ||
48 | static int scale_length(int length, int offset, float scale) { | ||
49 | return round((offset + length) * scale) - round(offset * scale); | ||
50 | } | ||
51 | |||
36 | static void scale_box(struct wlr_box *box, float scale) { | 52 | static void scale_box(struct wlr_box *box, float scale) { |
37 | box->x *= scale; | 53 | box->width = scale_length(box->width, box->x, scale); |
38 | box->y *= scale; | 54 | box->height = scale_length(box->height, box->y, scale); |
39 | box->width *= scale; | 55 | box->x = round(box->x * scale); |
40 | box->height *= scale; | 56 | box->y = round(box->y * scale); |
41 | } | 57 | } |
42 | 58 | ||
43 | static void scissor_output(struct wlr_output *wlr_output, | 59 | static void scissor_output(struct wlr_output *wlr_output, |
@@ -392,14 +408,23 @@ static void render_titlebar(struct sway_output *output, | |||
392 | render_rect(output->wlr_output, output_damage, &box, color); | 408 | render_rect(output->wlr_output, output_damage, &box, color); |
393 | 409 | ||
394 | // Single pixel right edge | 410 | // Single pixel right edge |
395 | box.x = (x + width - TITLEBAR_BORDER_THICKNESS) * output_scale; | 411 | box.x = x + width - TITLEBAR_BORDER_THICKNESS; |
412 | box.y = y + TITLEBAR_BORDER_THICKNESS; | ||
413 | box.width = TITLEBAR_BORDER_THICKNESS; | ||
414 | box.height = | ||
415 | container_titlebar_height() - TITLEBAR_BORDER_THICKNESS * 2; | ||
416 | scale_box(&box, output_scale); | ||
396 | render_rect(output->wlr_output, output_damage, &box, color); | 417 | render_rect(output->wlr_output, output_damage, &box, color); |
397 | } | 418 | } |
398 | 419 | ||
399 | size_t inner_width = width - TITLEBAR_H_PADDING * 2; | 420 | size_t inner_width = width - TITLEBAR_H_PADDING * 2; |
421 | int bg_y = y + TITLEBAR_BORDER_THICKNESS; | ||
422 | int ob_bg_height = scale_length( | ||
423 | (TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS) * 2 + | ||
424 | config->font_height, bg_y, output_scale); | ||
400 | 425 | ||
401 | // Marks | 426 | // Marks |
402 | size_t marks_ob_width = 0; // output-buffer-local | 427 | int marks_ob_width = 0; // output-buffer-local |
403 | if (config->show_marks && marks_texture) { | 428 | if (config->show_marks && marks_texture) { |
404 | struct wlr_box texture_box; | 429 | struct wlr_box texture_box; |
405 | wlr_texture_get_size(marks_texture, | 430 | wlr_texture_get_size(marks_texture, |
@@ -408,15 +433,14 @@ static void render_titlebar(struct sway_output *output, | |||
408 | 433 | ||
409 | // The marks texture might be shorter than the config->font_height, in | 434 | // The marks texture might be shorter than the config->font_height, in |
410 | // which case we need to pad it as evenly as possible above and below. | 435 | // which case we need to pad it as evenly as possible above and below. |
411 | int ob_padding_total = config->font_height * output_scale - | 436 | int ob_padding_total = ob_bg_height - texture_box.height; |
412 | texture_box.height; | 437 | int ob_padding_above = floor(ob_padding_total / 2.0); |
413 | int ob_padding_above = floor(ob_padding_total / 2); | 438 | int ob_padding_below = ceil(ob_padding_total / 2.0); |
414 | int ob_padding_below = ceil(ob_padding_total / 2); | ||
415 | 439 | ||
416 | // Render texture | 440 | // Render texture |
417 | texture_box.x = (x - output_x + width - TITLEBAR_H_PADDING) | 441 | texture_box.x = round((x - output_x + width - TITLEBAR_H_PADDING) |
418 | * output_scale - texture_box.width; | 442 | * output_scale) - texture_box.width; |
419 | texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale + | 443 | texture_box.y = round((bg_y - output_y) * output_scale) + |
420 | ob_padding_above; | 444 | ob_padding_above; |
421 | 445 | ||
422 | float matrix[9]; | 446 | float matrix[9]; |
@@ -431,29 +455,18 @@ static void render_titlebar(struct sway_output *output, | |||
431 | &texture_box, matrix, con->alpha); | 455 | &texture_box, matrix, con->alpha); |
432 | 456 | ||
433 | // Padding above | 457 | // Padding above |
434 | if (ob_padding_above > 0) { | 458 | memcpy(&color, colors->background, sizeof(float) * 4); |
435 | memcpy(&color, colors->background, sizeof(float) * 4); | 459 | premultiply_alpha(color, con->alpha); |
436 | premultiply_alpha(color, con->alpha); | 460 | box.x = texture_box.x + round(output_x * output_scale); |
437 | box.x = (x + width - TITLEBAR_H_PADDING) * output_scale - | 461 | box.y = round((y + TITLEBAR_BORDER_THICKNESS) * output_scale); |
438 | texture_box.width; | 462 | box.width = texture_box.width; |
439 | box.y = (y + TITLEBAR_V_PADDING) * output_scale; | 463 | box.height = ob_padding_above; |
440 | box.width = texture_box.width; | 464 | render_rect(output->wlr_output, output_damage, &box, color); |
441 | box.height = ob_padding_above; | ||
442 | render_rect(output->wlr_output, output_damage, &box, color); | ||
443 | } | ||
444 | 465 | ||
445 | // Padding below | 466 | // Padding below |
446 | if (ob_padding_below > 0) { | 467 | box.y += ob_padding_above + texture_box.height; |
447 | memcpy(&color, colors->background, sizeof(float) * 4); | 468 | box.height = ob_padding_below; |
448 | premultiply_alpha(color, con->alpha); | 469 | render_rect(output->wlr_output, output_damage, &box, color); |
449 | box.x = (x + width - TITLEBAR_H_PADDING) * output_scale - | ||
450 | texture_box.width; | ||
451 | box.y = (y + TITLEBAR_V_PADDING) * output_scale + | ||
452 | ob_padding_above + texture_box.height; | ||
453 | box.width = texture_box.width; | ||
454 | box.height = ob_padding_below; | ||
455 | render_rect(output->wlr_output, output_damage, &box, color); | ||
456 | } | ||
457 | } | 470 | } |
458 | 471 | ||
459 | // Title text | 472 | // Title text |
@@ -466,89 +479,73 @@ static void render_titlebar(struct sway_output *output, | |||
466 | 479 | ||
467 | // The title texture might be shorter than the config->font_height, | 480 | // The title texture might be shorter than the config->font_height, |
468 | // in which case we need to pad it above and below. | 481 | // in which case we need to pad it above and below. |
469 | int ob_padding_above = (config->font_baseline - con->title_baseline) | 482 | int ob_padding_above = round((config->font_baseline - |
470 | * output_scale; | 483 | con->title_baseline + TITLEBAR_V_PADDING - |
471 | int ob_padding_below = (config->font_height - con->title_height) | 484 | TITLEBAR_BORDER_THICKNESS) * output_scale); |
472 | * output_scale - ob_padding_above; | 485 | int ob_padding_below = ob_bg_height - ob_padding_above - |
486 | texture_box.height; | ||
473 | 487 | ||
474 | // Render texture | 488 | // Render texture |
475 | texture_box.x = (x - output_x + TITLEBAR_H_PADDING) * output_scale; | 489 | texture_box.x = |
476 | texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale + | 490 | round((x - output_x + TITLEBAR_H_PADDING) * output_scale); |
477 | ob_padding_above; | 491 | texture_box.y = |
492 | round((bg_y - output_y) * output_scale) + ob_padding_above; | ||
478 | 493 | ||
479 | float matrix[9]; | 494 | float matrix[9]; |
480 | wlr_matrix_project_box(matrix, &texture_box, | 495 | wlr_matrix_project_box(matrix, &texture_box, |
481 | WL_OUTPUT_TRANSFORM_NORMAL, | 496 | WL_OUTPUT_TRANSFORM_NORMAL, |
482 | 0.0, output->wlr_output->transform_matrix); | 497 | 0.0, output->wlr_output->transform_matrix); |
483 | 498 | ||
484 | if (inner_width * output_scale - marks_ob_width < texture_box.width) { | 499 | int inner_x = x - output_x + TITLEBAR_H_PADDING; |
485 | texture_box.width = inner_width * output_scale - marks_ob_width; | 500 | int ob_inner_width = scale_length(inner_width, inner_x, output_scale); |
501 | if (ob_inner_width - marks_ob_width < texture_box.width) { | ||
502 | texture_box.width = ob_inner_width - marks_ob_width; | ||
486 | } | 503 | } |
487 | render_texture(output->wlr_output, output_damage, title_texture, | 504 | render_texture(output->wlr_output, output_damage, title_texture, |
488 | &texture_box, matrix, con->alpha); | 505 | &texture_box, matrix, con->alpha); |
489 | 506 | ||
490 | // Padding above | 507 | // Padding above |
491 | if (ob_padding_above > 0) { | 508 | memcpy(&color, colors->background, sizeof(float) * 4); |
492 | memcpy(&color, colors->background, sizeof(float) * 4); | 509 | premultiply_alpha(color, con->alpha); |
493 | premultiply_alpha(color, con->alpha); | 510 | box.x = texture_box.x + round(output_x * output_scale); |
494 | box.x = (x + TITLEBAR_H_PADDING) * output_scale; | 511 | box.y = round((y + TITLEBAR_BORDER_THICKNESS) * output_scale); |
495 | box.y = (y + TITLEBAR_V_PADDING) * output_scale; | 512 | box.width = texture_box.width; |
496 | box.width = texture_box.width; | 513 | box.height = ob_padding_above; |
497 | box.height = ob_padding_above; | 514 | render_rect(output->wlr_output, output_damage, &box, color); |
498 | render_rect(output->wlr_output, output_damage, &box, color); | ||
499 | } | ||
500 | 515 | ||
501 | // Padding below | 516 | // Padding below |
502 | if (ob_padding_below > 0) { | 517 | box.y += ob_padding_above + texture_box.height; |
503 | memcpy(&color, colors->background, sizeof(float) * 4); | 518 | box.height = ob_padding_below; |
504 | premultiply_alpha(color, con->alpha); | 519 | render_rect(output->wlr_output, output_damage, &box, color); |
505 | box.x = (x + TITLEBAR_H_PADDING) * output_scale; | ||
506 | box.y = (y + TITLEBAR_V_PADDING) * output_scale + | ||
507 | ob_padding_above + texture_box.height; | ||
508 | box.width = texture_box.width; | ||
509 | box.height = ob_padding_below; | ||
510 | render_rect(output->wlr_output, output_damage, &box, color); | ||
511 | } | ||
512 | } | 520 | } |
513 | 521 | ||
514 | // Padding above title | ||
515 | memcpy(&color, colors->background, sizeof(float) * 4); | ||
516 | premultiply_alpha(color, con->alpha); | ||
517 | box.x = x + (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS; | ||
518 | box.y = y + TITLEBAR_BORDER_THICKNESS; | ||
519 | box.width = width - (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS * 2; | ||
520 | box.height = TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS; | ||
521 | scale_box(&box, output_scale); | ||
522 | render_rect(output->wlr_output, output_damage, &box, color); | ||
523 | |||
524 | // Padding below title | ||
525 | box.y = (y + TITLEBAR_V_PADDING + config->font_height) * output_scale; | ||
526 | render_rect(output->wlr_output, output_damage, &box, color); | ||
527 | |||
528 | // Filler between title and marks | 522 | // Filler between title and marks |
529 | box.width = inner_width * output_scale - title_ob_width - marks_ob_width; | 523 | box.width = |
524 | round(inner_width * output_scale) - title_ob_width - marks_ob_width; | ||
530 | if (box.width > 0) { | 525 | if (box.width > 0) { |
531 | box.x = (x + TITLEBAR_H_PADDING) * output_scale + title_ob_width; | 526 | box.x = round((x + TITLEBAR_H_PADDING) * output_scale) + title_ob_width; |
532 | box.y = (y + TITLEBAR_V_PADDING) * output_scale; | 527 | box.y = round(bg_y * output_scale); |
533 | box.height = config->font_height * output_scale; | 528 | box.height = ob_bg_height; |
534 | render_rect(output->wlr_output, output_damage, &box, color); | 529 | render_rect(output->wlr_output, output_damage, &box, color); |
535 | } | 530 | } |
536 | 531 | ||
537 | // Padding left of title | 532 | // Padding left of title |
538 | left_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS; | 533 | left_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS; |
539 | box.x = x + left_offset; | 534 | box.x = x + left_offset; |
540 | box.y = y + TITLEBAR_V_PADDING; | 535 | box.y = y + TITLEBAR_BORDER_THICKNESS; |
541 | box.width = TITLEBAR_H_PADDING - left_offset; | 536 | box.width = TITLEBAR_H_PADDING - left_offset; |
542 | box.height = config->font_height; | 537 | box.height = (TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS) * 2 + |
538 | config->font_height; | ||
543 | scale_box(&box, output_scale); | 539 | scale_box(&box, output_scale); |
544 | render_rect(output->wlr_output, output_damage, &box, color); | 540 | render_rect(output->wlr_output, output_damage, &box, color); |
545 | 541 | ||
546 | // Padding right of marks | 542 | // Padding right of marks |
547 | right_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS; | 543 | right_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS; |
548 | box.x = x + width - TITLEBAR_H_PADDING; | 544 | box.x = x + width - TITLEBAR_H_PADDING; |
549 | box.y = y + TITLEBAR_V_PADDING; | 545 | box.y = y + TITLEBAR_BORDER_THICKNESS; |
550 | box.width = TITLEBAR_H_PADDING - right_offset; | 546 | box.width = TITLEBAR_H_PADDING - right_offset; |
551 | box.height = config->font_height; | 547 | box.height = (TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS) * 2 + |
548 | config->font_height; | ||
552 | scale_box(&box, output_scale); | 549 | scale_box(&box, output_scale); |
553 | render_rect(output->wlr_output, output_damage, &box, color); | 550 | render_rect(output->wlr_output, output_damage, &box, color); |
554 | 551 | ||
diff --git a/sway/input/cursor.c b/sway/input/cursor.c index 21e104ec..925190d6 100644 --- a/sway/input/cursor.c +++ b/sway/input/cursor.c | |||
@@ -597,7 +597,7 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, | |||
597 | struct sway_output *focused_output = node_get_output(focus); | 597 | struct sway_output *focused_output = node_get_output(focus); |
598 | struct sway_output *output = node_get_output(node); | 598 | struct sway_output *output = node_get_output(node); |
599 | if (output != focused_output) { | 599 | if (output != focused_output) { |
600 | seat_set_focus_warp(seat, node, false, true); | 600 | seat_set_focus_warp(seat, node, false); |
601 | } | 601 | } |
602 | } else if (node->type == N_CONTAINER && node->sway_container->view) { | 602 | } else if (node->type == N_CONTAINER && node->sway_container->view) { |
603 | // Focus node if the following are true: | 603 | // Focus node if the following are true: |
@@ -607,14 +607,14 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec, | |||
607 | if (!wlr_seat_keyboard_has_grab(cursor->seat->wlr_seat) && | 607 | if (!wlr_seat_keyboard_has_grab(cursor->seat->wlr_seat) && |
608 | node != prev_node && | 608 | node != prev_node && |
609 | view_is_visible(node->sway_container->view)) { | 609 | view_is_visible(node->sway_container->view)) { |
610 | seat_set_focus_warp(seat, node, false, true); | 610 | seat_set_focus_warp(seat, node, false); |
611 | } else { | 611 | } else { |
612 | struct sway_node *next_focus = | 612 | struct sway_node *next_focus = |
613 | seat_get_focus_inactive(seat, &root->node); | 613 | seat_get_focus_inactive(seat, &root->node); |
614 | if (next_focus && next_focus->type == N_CONTAINER && | 614 | if (next_focus && next_focus->type == N_CONTAINER && |
615 | next_focus->sway_container->view && | 615 | next_focus->sway_container->view && |
616 | view_is_visible(next_focus->sway_container->view)) { | 616 | view_is_visible(next_focus->sway_container->view)) { |
617 | seat_set_focus_warp(seat, next_focus, false, true); | 617 | seat_set_focus_warp(seat, next_focus, false); |
618 | } | 618 | } |
619 | } | 619 | } |
620 | } | 620 | } |
diff --git a/sway/input/keyboard.c b/sway/input/keyboard.c index fb1fe7b5..2c8b41cd 100644 --- a/sway/input/keyboard.c +++ b/sway/input/keyboard.c | |||
@@ -9,6 +9,7 @@ | |||
9 | #include "sway/input/input-manager.h" | 9 | #include "sway/input/input-manager.h" |
10 | #include "sway/input/keyboard.h" | 10 | #include "sway/input/keyboard.h" |
11 | #include "sway/input/seat.h" | 11 | #include "sway/input/seat.h" |
12 | #include "sway/ipc-server.h" | ||
12 | #include "log.h" | 13 | #include "log.h" |
13 | 14 | ||
14 | /** | 15 | /** |
@@ -66,10 +67,10 @@ static void update_shortcut_state(struct sway_shortcut_state *state, | |||
66 | bool last_key_was_a_modifier = raw_modifiers != state->last_raw_modifiers; | 67 | bool last_key_was_a_modifier = raw_modifiers != state->last_raw_modifiers; |
67 | state->last_raw_modifiers = raw_modifiers; | 68 | state->last_raw_modifiers = raw_modifiers; |
68 | 69 | ||
69 | if (last_key_was_a_modifier && state->last_keycode) { | 70 | if (last_key_was_a_modifier && state->last_keycode) { |
70 | // Last pressed key before this one was a modifier | 71 | // Last pressed key before this one was a modifier |
71 | state_erase_key(state, state->last_keycode); | 72 | state_erase_key(state, state->last_keycode); |
72 | } | 73 | } |
73 | 74 | ||
74 | if (event->state == WLR_KEY_PRESSED) { | 75 | if (event->state == WLR_KEY_PRESSED) { |
75 | // Add current key to set; there may be duplicates | 76 | // Add current key to set; there may be duplicates |
@@ -235,7 +236,6 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) { | |||
235 | code_modifiers); | 236 | code_modifiers); |
236 | } | 237 | } |
237 | 238 | ||
238 | |||
239 | bool handled = false; | 239 | bool handled = false; |
240 | 240 | ||
241 | // Identify active release binding | 241 | // Identify active release binding |
@@ -337,6 +337,19 @@ static int handle_keyboard_repeat(void *data) { | |||
337 | return 0; | 337 | return 0; |
338 | } | 338 | } |
339 | 339 | ||
340 | static void determine_bar_visibility(uint32_t modifiers) { | ||
341 | for (int i = 0; i < config->bars->length; ++i) { | ||
342 | struct bar_config *bar = config->bars->items[i]; | ||
343 | if (strcmp(bar->mode, bar->hidden_state) == 0) { // both are "hide" | ||
344 | bool should_be_visible = (~modifiers & bar->modifier) == 0; | ||
345 | if (bar->visible_by_modifier != should_be_visible) { | ||
346 | bar->visible_by_modifier = should_be_visible; | ||
347 | ipc_event_bar_state_update(bar); | ||
348 | } | ||
349 | } | ||
350 | } | ||
351 | } | ||
352 | |||
340 | static void handle_keyboard_modifiers(struct wl_listener *listener, | 353 | static void handle_keyboard_modifiers(struct wl_listener *listener, |
341 | void *data) { | 354 | void *data) { |
342 | struct sway_keyboard *keyboard = | 355 | struct sway_keyboard *keyboard = |
@@ -346,6 +359,9 @@ static void handle_keyboard_modifiers(struct wl_listener *listener, | |||
346 | keyboard->seat_device->input_device->wlr_device; | 359 | keyboard->seat_device->input_device->wlr_device; |
347 | wlr_seat_set_keyboard(wlr_seat, wlr_device); | 360 | wlr_seat_set_keyboard(wlr_seat, wlr_device); |
348 | wlr_seat_keyboard_notify_modifiers(wlr_seat, &wlr_device->keyboard->modifiers); | 361 | wlr_seat_keyboard_notify_modifiers(wlr_seat, &wlr_device->keyboard->modifiers); |
362 | |||
363 | uint32_t modifiers = wlr_keyboard_get_modifiers(wlr_device->keyboard); | ||
364 | determine_bar_visibility(modifiers); | ||
349 | } | 365 | } |
350 | 366 | ||
351 | struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, | 367 | struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat, |
@@ -464,7 +480,7 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) { | |||
464 | keyboard->keyboard_key.notify = handle_keyboard_key; | 480 | keyboard->keyboard_key.notify = handle_keyboard_key; |
465 | 481 | ||
466 | wl_list_remove(&keyboard->keyboard_modifiers.link); | 482 | wl_list_remove(&keyboard->keyboard_modifiers.link); |
467 | wl_signal_add( &wlr_device->keyboard->events.modifiers, | 483 | wl_signal_add(&wlr_device->keyboard->events.modifiers, |
468 | &keyboard->keyboard_modifiers); | 484 | &keyboard->keyboard_modifiers); |
469 | keyboard->keyboard_modifiers.notify = handle_keyboard_modifiers; | 485 | keyboard->keyboard_modifiers.notify = handle_keyboard_modifiers; |
470 | } | 486 | } |
diff --git a/sway/input/seat.c b/sway/input/seat.c index 23f582ca..d8d2f3a4 100644 --- a/sway/input/seat.c +++ b/sway/input/seat.c | |||
@@ -184,8 +184,8 @@ static void handle_seat_node_destroy(struct wl_listener *listener, void *data) { | |||
184 | seat_set_focus(seat, next_focus); | 184 | seat_set_focus(seat, next_focus); |
185 | } else { | 185 | } else { |
186 | // Setting focus_inactive | 186 | // Setting focus_inactive |
187 | seat_set_focus_warp(seat, next_focus, false, false); | 187 | seat_set_raw_focus(seat, next_focus); |
188 | seat_set_focus_warp(seat, focus, false, false); | 188 | seat_set_raw_focus(seat, focus); |
189 | } | 189 | } |
190 | } | 190 | } |
191 | 191 | ||
@@ -623,8 +623,25 @@ static void container_raise_floating(struct sway_container *con) { | |||
623 | } | 623 | } |
624 | } | 624 | } |
625 | 625 | ||
626 | static void set_workspace(struct sway_seat *seat, | ||
627 | struct sway_workspace *new_ws) { | ||
628 | if (seat->workspace == new_ws) { | ||
629 | return; | ||
630 | } | ||
631 | ipc_event_workspace(seat->workspace, new_ws, "focus"); | ||
632 | seat->workspace = new_ws; | ||
633 | } | ||
634 | |||
635 | void seat_set_raw_focus(struct sway_seat *seat, struct sway_node *node) { | ||
636 | struct sway_seat_node *seat_node = seat_node_from_node(seat, node); | ||
637 | wl_list_remove(&seat_node->link); | ||
638 | wl_list_insert(&seat->focus_stack, &seat_node->link); | ||
639 | node_set_dirty(node); | ||
640 | node_set_dirty(node_get_parent(node)); | ||
641 | } | ||
642 | |||
626 | void seat_set_focus_warp(struct sway_seat *seat, struct sway_node *node, | 643 | void seat_set_focus_warp(struct sway_seat *seat, struct sway_node *node, |
627 | bool warp, bool notify) { | 644 | bool warp) { |
628 | if (seat->focused_layer) { | 645 | if (seat->focused_layer) { |
629 | return; | 646 | return; |
630 | } | 647 | } |
@@ -688,34 +705,20 @@ void seat_set_focus_warp(struct sway_seat *seat, struct sway_node *node, | |||
688 | if (container) { | 705 | if (container) { |
689 | struct sway_container *parent = container->parent; | 706 | struct sway_container *parent = container->parent; |
690 | while (parent) { | 707 | while (parent) { |
691 | struct sway_seat_node *seat_node = | 708 | seat_set_raw_focus(seat, &parent->node); |
692 | seat_node_from_node(seat, &parent->node); | ||
693 | wl_list_remove(&seat_node->link); | ||
694 | wl_list_insert(&seat->focus_stack, &seat_node->link); | ||
695 | node_set_dirty(&parent->node); | ||
696 | parent = parent->parent; | 709 | parent = parent->parent; |
697 | } | 710 | } |
698 | } | 711 | } |
699 | if (new_workspace) { | 712 | if (new_workspace) { |
700 | struct sway_seat_node *seat_node = | 713 | seat_set_raw_focus(seat, &new_workspace->node); |
701 | seat_node_from_node(seat, &new_workspace->node); | ||
702 | wl_list_remove(&seat_node->link); | ||
703 | wl_list_insert(&seat->focus_stack, &seat_node->link); | ||
704 | node_set_dirty(&new_workspace->node); | ||
705 | } | 714 | } |
706 | if (container) { | 715 | if (container) { |
707 | struct sway_seat_node *seat_node = | 716 | seat_set_raw_focus(seat, &container->node); |
708 | seat_node_from_node(seat, &container->node); | ||
709 | wl_list_remove(&seat_node->link); | ||
710 | wl_list_insert(&seat->focus_stack, &seat_node->link); | ||
711 | node_set_dirty(&container->node); | ||
712 | seat_send_focus(&container->node, seat); | 717 | seat_send_focus(&container->node, seat); |
713 | } | 718 | } |
714 | 719 | ||
715 | // emit ipc events | 720 | // emit ipc events |
716 | if (notify && new_workspace && last_workspace != new_workspace) { | 721 | set_workspace(seat, new_workspace); |
717 | ipc_event_workspace(last_workspace, new_workspace, "focus"); | ||
718 | } | ||
719 | if (container && container->view) { | 722 | if (container && container->view) { |
720 | ipc_event_window(container, "focus"); | 723 | ipc_event_window(container, "focus"); |
721 | } | 724 | } |
@@ -798,17 +801,17 @@ void seat_set_focus_warp(struct sway_seat *seat, struct sway_node *node, | |||
798 | } | 801 | } |
799 | 802 | ||
800 | void seat_set_focus(struct sway_seat *seat, struct sway_node *node) { | 803 | void seat_set_focus(struct sway_seat *seat, struct sway_node *node) { |
801 | seat_set_focus_warp(seat, node, true, true); | 804 | seat_set_focus_warp(seat, node, true); |
802 | } | 805 | } |
803 | 806 | ||
804 | void seat_set_focus_container(struct sway_seat *seat, | 807 | void seat_set_focus_container(struct sway_seat *seat, |
805 | struct sway_container *con) { | 808 | struct sway_container *con) { |
806 | seat_set_focus_warp(seat, con ? &con->node : NULL, true, true); | 809 | seat_set_focus_warp(seat, con ? &con->node : NULL, true); |
807 | } | 810 | } |
808 | 811 | ||
809 | void seat_set_focus_workspace(struct sway_seat *seat, | 812 | void seat_set_focus_workspace(struct sway_seat *seat, |
810 | struct sway_workspace *ws) { | 813 | struct sway_workspace *ws) { |
811 | seat_set_focus_warp(seat, ws ? &ws->node : NULL, true, true); | 814 | seat_set_focus_warp(seat, ws ? &ws->node : NULL, true); |
812 | } | 815 | } |
813 | 816 | ||
814 | void seat_set_focus_surface(struct sway_seat *seat, | 817 | void seat_set_focus_surface(struct sway_seat *seat, |
diff --git a/sway/ipc-server.c b/sway/ipc-server.c index 2d915502..63c95503 100644 --- a/sway/ipc-server.c +++ b/sway/ipc-server.c | |||
@@ -349,6 +349,22 @@ void ipc_event_barconfig_update(struct bar_config *bar) { | |||
349 | json_object_put(json); | 349 | json_object_put(json); |
350 | } | 350 | } |
351 | 351 | ||
352 | void ipc_event_bar_state_update(struct bar_config *bar) { | ||
353 | if (!ipc_has_event_listeners(IPC_EVENT_BAR_STATE_UPDATE)) { | ||
354 | return; | ||
355 | } | ||
356 | wlr_log(WLR_DEBUG, "Sending bar_state_update event"); | ||
357 | |||
358 | json_object *json = json_object_new_object(); | ||
359 | json_object_object_add(json, "id", json_object_new_string(bar->id)); | ||
360 | json_object_object_add(json, "visible_by_modifier", | ||
361 | json_object_new_boolean(bar->visible_by_modifier)); | ||
362 | |||
363 | const char *json_string = json_object_to_json_string(json); | ||
364 | ipc_send_event(json_string, IPC_EVENT_BAR_STATE_UPDATE); | ||
365 | json_object_put(json); | ||
366 | } | ||
367 | |||
352 | void ipc_event_mode(const char *mode, bool pango) { | 368 | void ipc_event_mode(const char *mode, bool pango) { |
353 | if (!ipc_has_event_listeners(IPC_EVENT_MODE)) { | 369 | if (!ipc_has_event_listeners(IPC_EVENT_MODE)) { |
354 | return; | 370 | return; |
@@ -651,6 +667,8 @@ void ipc_client_handle_command(struct ipc_client *client) { | |||
651 | client->subscribed_events |= event_mask(IPC_EVENT_WORKSPACE); | 667 | client->subscribed_events |= event_mask(IPC_EVENT_WORKSPACE); |
652 | } else if (strcmp(event_type, "barconfig_update") == 0) { | 668 | } else if (strcmp(event_type, "barconfig_update") == 0) { |
653 | client->subscribed_events |= event_mask(IPC_EVENT_BARCONFIG_UPDATE); | 669 | client->subscribed_events |= event_mask(IPC_EVENT_BARCONFIG_UPDATE); |
670 | } else if (strcmp(event_type, "bar_state_update") == 0) { | ||
671 | client->subscribed_events |= event_mask(IPC_EVENT_BAR_STATE_UPDATE); | ||
654 | } else if (strcmp(event_type, "mode") == 0) { | 672 | } else if (strcmp(event_type, "mode") == 0) { |
655 | client->subscribed_events |= event_mask(IPC_EVENT_MODE); | 673 | client->subscribed_events |= event_mask(IPC_EVENT_MODE); |
656 | } else if (strcmp(event_type, "shutdown") == 0) { | 674 | } else if (strcmp(event_type, "shutdown") == 0) { |
diff --git a/sway/main.c b/sway/main.c index dea4a31c..8d39d5f1 100644 --- a/sway/main.c +++ b/sway/main.c | |||
@@ -287,7 +287,6 @@ int main(int argc, char **argv) { | |||
287 | } | 287 | } |
288 | } | 288 | } |
289 | 289 | ||
290 | // TODO: switch logging over to wlroots? | ||
291 | if (debug) { | 290 | if (debug) { |
292 | wlr_log_init(WLR_DEBUG, NULL); | 291 | wlr_log_init(WLR_DEBUG, NULL); |
293 | } else if (verbose || validate) { | 292 | } else if (verbose || validate) { |
diff --git a/sway/sway-bar.5.scd b/sway/sway-bar.5.scd index 6729c9ac..873741c0 100644 --- a/sway/sway-bar.5.scd +++ b/sway/sway-bar.5.scd | |||
@@ -65,6 +65,22 @@ Sway allows configuring swaybar in the sway configuration file. | |||
65 | is given, when mouse button _n_ has been released). To disable the default | 65 | is given, when mouse button _n_ has been released). To disable the default |
66 | behavior for a button, use the command _nop_. | 66 | behavior for a button, use the command _nop_. |
67 | 67 | ||
68 | *mode* dock|hide|invisible | ||
69 | Specifies the visibility of the bar. In _dock_ mode, it is permanently | ||
70 | visible at one edge of the screen. In _hide_ mode, it is hidden unless the | ||
71 | modifier key is pressed, though this behaviour depends on the hidden state. | ||
72 | In _invisible_ mode, it is permanently hidden. Default is _dock_. | ||
73 | |||
74 | *hidden\_state* hide|show | ||
75 | Specifies the behaviour of the bar when it is in _hide_ mode. When the | ||
76 | hidden state is _hide_, then it is normally hidden, and only unhidden by | ||
77 | pressing the modifier key or in case of urgency hints. When the hidden | ||
78 | state is _show_, then it is permanently visible, drawn on top of the | ||
79 | currently visible workspace. Default is _hide_. | ||
80 | |||
81 | *modifier* <Modifier>|none | ||
82 | Specifies the modifier key that shows a hidden bar. Default is _Mod4_. | ||
83 | |||
68 | ## TRAY | 84 | ## TRAY |
69 | 85 | ||
70 | Swaybar provides a system tray where third-party applications may place icons. | 86 | Swaybar provides a system tray where third-party applications may place icons. |
diff --git a/sway/sway-input.5.scd b/sway/sway-input.5.scd index e5673452..82273ef3 100644 --- a/sway/sway-input.5.scd +++ b/sway/sway-input.5.scd | |||
@@ -143,4 +143,4 @@ in their own "seat"). | |||
143 | 143 | ||
144 | # SEE ALSO | 144 | # SEE ALSO |
145 | 145 | ||
146 | *sway*(5) | 146 | *sway*(5) *sway-output*(5) |
diff --git a/sway/sway-output.5.scd b/sway/sway-output.5.scd new file mode 100644 index 00000000..fe5b33bc --- /dev/null +++ b/sway/sway-output.5.scd | |||
@@ -0,0 +1,66 @@ | |||
1 | sway-output(5) | ||
2 | |||
3 | # NAME | ||
4 | |||
5 | sway-output - output configuration commands for sway | ||
6 | |||
7 | # DESCRIPTION | ||
8 | |||
9 | You may combine output commands into one, like so: | ||
10 | |||
11 | output HDMI-A-1 mode 1920x1080 pos 1920,0 bg ~/wallpaper.png stretch | ||
12 | |||
13 | You can get a list of output names with *swaymsg -t get\_outputs*. You may also | ||
14 | match any output by using the output name "\*". | ||
15 | |||
16 | # COMMANDS | ||
17 | |||
18 | *output* <name> mode|resolution|res <WIDTHxHEIGHT>[@<RATE>[Hz]] | ||
19 | Configures the specified output to use the given mode. Modes are a | ||
20 | combination of width and height (in pixels) and a refresh rate that your | ||
21 | display can be configured to use. For a list of available modes for each | ||
22 | output, use *swaymsg -t get\_outputs*. | ||
23 | |||
24 | Examples: | ||
25 | |||
26 | output HDMI-A-1 mode 1920x1080 | ||
27 | |||
28 | output HDMI-A-1 mode 1920x1080@60Hz | ||
29 | |||
30 | *output* <name> position|pos <X> <Y> | ||
31 | Places the specified output at the specific position in the global | ||
32 | coordinate space. | ||
33 | |||
34 | *output* <name> scale <factor> | ||
35 | Scales the specified output by the specified scale _factor_. An integer is | ||
36 | recommended, but fractional values are also supported. If a fractional | ||
37 | value are specified, be warned that it is not possible to faithfully | ||
38 | represent the contents of your windows - they will be rendered at the next | ||
39 | highest integral scale factor and downscaled. You may be better served by | ||
40 | setting an integral scale factor and adjusting the font size of your | ||
41 | applications to taste. | ||
42 | |||
43 | *output* <name> background|bg <file> <mode> [<fallback\_color>] | ||
44 | Sets the wallpaper for the given output to the specified file, using the | ||
45 | given scaling mode (one of "stretch", "fill", "fit", "center", "tile"). If | ||
46 | the specified file cannot be accessed or if the image does fill the entire | ||
47 | output, a fallback color may be provided to cover the rest of the output. | ||
48 | __fallback\_color__ should be specified as _#RRGGBB_. Alpha is not | ||
49 | supported. | ||
50 | |||
51 | *output* <name> background|bg <color> solid\_color | ||
52 | Sets the background of the given output to the specified color. _color_ | ||
53 | should be specified as _#RRGGBB_. Alpha is not supported. | ||
54 | |||
55 | *output* <name> transform <transform> | ||
56 | Sets the background transform to the given value. Can be one of "90", "180", | ||
57 | "270" for rotation; or "flipped", "flipped-90", "flipped-180", "flipped-270" | ||
58 | to apply a rotation and flip, or "normal" to apply no transform. | ||
59 | |||
60 | *output* <name> disable|enable | ||
61 | Enables or disables the specified output (all outputs are enabled by | ||
62 | default). | ||
63 | |||
64 | # SEE ALSO | ||
65 | |||
66 | *sway*(5) *sway-input*(5) | ||
diff --git a/sway/sway.1.scd b/sway/sway.1.scd index 0c2ee974..f66c4cdb 100644 --- a/sway/sway.1.scd +++ b/sway/sway.1.scd | |||
@@ -92,4 +92,4 @@ source contributors. For more information about sway development, see | |||
92 | 92 | ||
93 | # SEE ALSO | 93 | # SEE ALSO |
94 | 94 | ||
95 | *sway*(5) *swaymsg*(1) *sway-input*(5) *sway-bar*(5) | 95 | *sway*(5) *swaymsg*(1) *sway-input*(5) *sway-output*(5) *sway-bar*(5) |
diff --git a/sway/sway.5.scd b/sway/sway.5.scd index 240e0731..f6f0e859 100644 --- a/sway/sway.5.scd +++ b/sway/sway.5.scd | |||
@@ -87,14 +87,15 @@ The following commands may only be used in the configuration file. | |||
87 | The following commands cannot be used directly in the configuration file. | 87 | The following commands cannot be used directly in the configuration file. |
88 | They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). | 88 | They are expected to be used with *bindsym* or at runtime through *swaymsg*(1). |
89 | 89 | ||
90 | *border* normal|pixel [<n>] | 90 | *border* none|normal|csd|pixel [<n>] |
91 | Set border style for focused window. _normal_ includes a border of | 91 | Set border style for focused window. _normal_ includes a border of |
92 | thickness _n_ and a title bar. _pixel_ is a border without title bar _n_ | 92 | thickness _n_ and a title bar. _pixel_ is a border without title bar _n_ |
93 | pixels thick. Default is _normal_ with border thickness 2. | 93 | pixels thick. Default is _normal_ with border thickness 2. _csd_ is short |
94 | for client-side-decorations, which allows the client to draw its own | ||
95 | decorations. | ||
94 | 96 | ||
95 | *border* none|toggle | 97 | *border* toggle |
96 | Set border style for focused window to _none_ or _toggle_ between the | 98 | Cycles through the available border styles. |
97 | available border styles: _normal_, _pixel_, _none_. | ||
98 | 99 | ||
99 | *exit* | 100 | *exit* |
100 | Exit sway and end your Wayland session. | 101 | Exit sway and end your Wayland session. |
@@ -420,15 +421,11 @@ The default colors are: | |||
420 | _focus\_wrapping force_. This is only available for convenience. Please | 421 | _focus\_wrapping force_. This is only available for convenience. Please |
421 | use _focus\_wrapping_ instead when possible. | 422 | use _focus\_wrapping_ instead when possible. |
422 | 423 | ||
423 | *gaps* edge\_gaps on|off|toggle | ||
424 | When _on_, gaps will be added between windows and workspace edges if the | ||
425 | inner gap is nonzero. When _off_, gaps will only be added between views. | ||
426 | _toggle_ cannot be used in the configuration file. | ||
427 | |||
428 | *gaps* inner|outer <amount> | 424 | *gaps* inner|outer <amount> |
429 | Sets default _amount_ pixels of _inner_ or _outer_ gap, where the inner | 425 | Sets default _amount_ pixels of _inner_ or _outer_ gap, where the inner |
430 | affects spacing around each view and outer affects the spacing around each | 426 | affects spacing around each view and outer affects the spacing around each |
431 | workspace. Outer gaps are in addition to inner gaps. | 427 | workspace. Outer gaps are in addition to inner gaps. To reduce or remove |
428 | outer gaps, outer gaps can be set to a negative value. | ||
432 | 429 | ||
433 | This affects new workspaces only, and is used when the workspace doesn't | 430 | This affects new workspaces only, and is used when the workspace doesn't |
434 | have its own gaps settings (see: workspace <ws> gaps inner|outer <amount>). | 431 | have its own gaps settings (see: workspace <ws> gaps inner|outer <amount>). |
@@ -501,61 +498,6 @@ The default colors are: | |||
501 | Prevents windows matching <criteria> from being focused automatically when | 498 | Prevents windows matching <criteria> from being focused automatically when |
502 | they're created. This has no effect on the first window in a workspace. | 499 | they're created. This has no effect on the first window in a workspace. |
503 | 500 | ||
504 | *output* <name> mode|resolution|res <WIDTHxHEIGHT>[@<RATE>[Hz]] | ||
505 | Configures the specified output to use the given mode. Modes are a | ||
506 | combination of width and height (in pixels) and a refresh rate that your | ||
507 | display can be configured to use. For a list of available modes for each | ||
508 | output, use *swaymsg -t get\_outputs*. | ||
509 | |||
510 | Examples: | ||
511 | |||
512 | output HDMI-A-1 mode 1920x1080 | ||
513 | |||
514 | output HDMI-A-1 mode 1920x1080@60Hz | ||
515 | |||
516 | *output* <name> position|pos <X> <Y> | ||
517 | Places the specified output at the specific position in the global | ||
518 | coordinate space. | ||
519 | |||
520 | *output* <name> scale <factor> | ||
521 | Scales the specified output by the specified scale _factor_. An integer is | ||
522 | recommended, but fractional values are also supported. If a fractional | ||
523 | value are specified, be warned that it is not possible to faithfully | ||
524 | represent the contents of your windows - they will be rendered at the next | ||
525 | highest integral scale factor and downscaled. You may be better served by | ||
526 | setting an integral scale factor and adjusting the font size of your | ||
527 | applications to taste. | ||
528 | |||
529 | *output* <name> background|bg <file> <mode> [<fallback\_color>] | ||
530 | Sets the wallpaper for the given output to the specified file, using the | ||
531 | given scaling mode (one of "stretch", "fill", "fit", "center", "tile"). If | ||
532 | the specified file cannot be accessed or if the image does fill the entire | ||
533 | output, a fallback color may be provided to cover the rest of the output. | ||
534 | __fallback\_color__ should be specified as _#RRGGBB_. Alpha is not | ||
535 | supported. | ||
536 | |||
537 | **output** <name> background|bg <color> solid\_color | ||
538 | Sets the background of the given output to the specified color. _color_ | ||
539 | should be specified as _#RRGGBB_. Alpha is not supported. | ||
540 | |||
541 | **output** <name> transform <transform> | ||
542 | Sets the background transform to the given value. Can be one of "90", "180", | ||
543 | "270" for rotation; or "flipped", "flipped-90", "flipped-180", "flipped-270" | ||
544 | to apply a rotation and flip, or "normal" to apply no transform. | ||
545 | |||
546 | *output* <name> disable|enable | ||
547 | Enables or disables the specified output (all outputs are enabled by | ||
548 | default). | ||
549 | |||
550 | *NOTES FOR THE OUTPUT COMMANDS* | ||
551 | |||
552 | You may combine output commands into one, like so: | ||
553 | |||
554 | output HDMI-A-1 mode 1920x1080 pos 1920,0 bg ~/wallpaper.png stretch | ||
555 | |||
556 | You can get a list of output names with *swaymsg -t get\_outputs*. You may also | ||
557 | match any output by using the output name "\*". | ||
558 | |||
559 | *popup\_during\_fullscreen* smart|ignore|leave\_fullscreen | 501 | *popup\_during\_fullscreen* smart|ignore|leave\_fullscreen |
560 | Determines what to do when a fullscreen view opens a dialog. | 502 | Determines what to do when a fullscreen view opens a dialog. |
561 | If _smart_ (the default), the dialog will be displayed. If _ignore_, the | 503 | If _smart_ (the default), the dialog will be displayed. If _ignore_, the |
@@ -618,6 +560,18 @@ match any output by using the output name "\*". | |||
618 | *workspace\_layout* default|stacking|tabbed | 560 | *workspace\_layout* default|stacking|tabbed |
619 | Specifies the initial layout for new workspaces. | 561 | Specifies the initial layout for new workspaces. |
620 | 562 | ||
563 | # BAR CONTROL | ||
564 | |||
565 | *bar hidden\_state* hide|show|toggle [<bar\_id>] | ||
566 | Sets the hidden state of the bar (see *sway-bar*(5)), either individually, | ||
567 | by specifying a bar id, or if none is given, for all bar instances. | ||
568 | _toggle_ switches between _hide_ and _show_. | ||
569 | |||
570 | *bar mode* dock|hide|invisible|toggle [<bar\_id>] | ||
571 | Sets the mode of the bar (see *sway-bar*(5)), either individually, | ||
572 | by specifying a bar id, or if none is given, for all bar instances. | ||
573 | _toggle_ switches between _dock_ and _hide_. | ||
574 | |||
621 | # CRITERIA | 575 | # CRITERIA |
622 | 576 | ||
623 | A criteria is a string in the form of, for example: | 577 | A criteria is a string in the form of, for example: |
diff --git a/sway/tree/arrange.c b/sway/tree/arrange.c index 373460a2..852d53bf 100644 --- a/sway/tree/arrange.c +++ b/sway/tree/arrange.c | |||
@@ -180,6 +180,10 @@ void arrange_workspace(struct sway_workspace *workspace) { | |||
180 | if (config->reloading) { | 180 | if (config->reloading) { |
181 | return; | 181 | return; |
182 | } | 182 | } |
183 | if (!workspace->output) { | ||
184 | // Happens when there are no outputs connected | ||
185 | return; | ||
186 | } | ||
183 | struct sway_output *output = workspace->output; | 187 | struct sway_output *output = workspace->output; |
184 | struct wlr_box *area = &output->usable_area; | 188 | struct wlr_box *area = &output->usable_area; |
185 | wlr_log(WLR_DEBUG, "Usable area for ws: %dx%d@%d,%d", | 189 | wlr_log(WLR_DEBUG, "Usable area for ws: %dx%d@%d,%d", |
diff --git a/sway/tree/container.c b/sway/tree/container.c index f36fe4b0..edab7a17 100644 --- a/sway/tree/container.c +++ b/sway/tree/container.c | |||
@@ -1202,8 +1202,8 @@ struct sway_container *container_split(struct sway_container *child, | |||
1202 | container_add_child(cont, child); | 1202 | container_add_child(cont, child); |
1203 | 1203 | ||
1204 | if (set_focus) { | 1204 | if (set_focus) { |
1205 | seat_set_focus_container(seat, cont); | 1205 | seat_set_raw_focus(seat, &cont->node); |
1206 | seat_set_focus_container(seat, child); | 1206 | seat_set_raw_focus(seat, &child->node); |
1207 | } | 1207 | } |
1208 | 1208 | ||
1209 | return cont; | 1209 | return cont; |
diff --git a/sway/tree/view.c b/sway/tree/view.c index 4b9bbfd0..85998547 100644 --- a/sway/tree/view.c +++ b/sway/tree/view.c | |||
@@ -504,7 +504,16 @@ static struct sway_workspace *select_workspace(struct sway_view *view) { | |||
504 | } | 504 | } |
505 | 505 | ||
506 | // Use the focused workspace | 506 | // Use the focused workspace |
507 | return seat_get_focused_workspace(seat); | 507 | struct sway_node *node = seat_get_focus_inactive(seat, &root->node); |
508 | if (node && node->type == N_WORKSPACE) { | ||
509 | return node->sway_workspace; | ||
510 | } else if (node && node->type == N_CONTAINER) { | ||
511 | return node->sway_container->workspace; | ||
512 | } | ||
513 | |||
514 | // If there's no focus_inactive workspace then we must be running without | ||
515 | // any outputs connected | ||
516 | return root->saved_workspaces->items[0]; | ||
508 | } | 517 | } |
509 | 518 | ||
510 | static bool should_focus(struct sway_view *view) { | 519 | static bool should_focus(struct sway_view *view) { |
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c index d7650560..a1282c1e 100644 --- a/sway/tree/workspace.c +++ b/sway/tree/workspace.c | |||
@@ -73,10 +73,10 @@ struct sway_workspace *workspace_create(struct sway_output *output, | |||
73 | if (name) { | 73 | if (name) { |
74 | struct workspace_config *wsc = workspace_find_config(name); | 74 | struct workspace_config *wsc = workspace_find_config(name); |
75 | if (wsc) { | 75 | if (wsc) { |
76 | if (wsc->gaps_outer != -1) { | 76 | if (wsc->gaps_outer != INT_MIN) { |
77 | ws->gaps_outer = wsc->gaps_outer; | 77 | ws->gaps_outer = wsc->gaps_outer; |
78 | } | 78 | } |
79 | if (wsc->gaps_inner != -1) { | 79 | if (wsc->gaps_inner != INT_MIN) { |
80 | ws->gaps_inner = wsc->gaps_inner; | 80 | ws->gaps_inner = wsc->gaps_inner; |
81 | } | 81 | } |
82 | } | 82 | } |
@@ -618,9 +618,6 @@ void workspace_add_gaps(struct sway_workspace *ws) { | |||
618 | if (ws->current_gaps > 0) { | 618 | if (ws->current_gaps > 0) { |
619 | return; | 619 | return; |
620 | } | 620 | } |
621 | if (!config->edge_gaps) { | ||
622 | return; | ||
623 | } | ||
624 | if (config->smart_gaps) { | 621 | if (config->smart_gaps) { |
625 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); | 622 | struct sway_seat *seat = input_manager_get_default_seat(input_manager); |
626 | struct sway_container *focus = | 623 | struct sway_container *focus = |
diff --git a/swaybar/bar.c b/swaybar/bar.c index 5b7fea71..0deba72d 100644 --- a/swaybar/bar.c +++ b/swaybar/bar.c | |||
@@ -18,7 +18,6 @@ | |||
18 | #endif | 18 | #endif |
19 | #include "swaybar/bar.h" | 19 | #include "swaybar/bar.h" |
20 | #include "swaybar/config.h" | 20 | #include "swaybar/config.h" |
21 | #include "swaybar/event_loop.h" | ||
22 | #include "swaybar/i3bar.h" | 21 | #include "swaybar/i3bar.h" |
23 | #include "swaybar/ipc.h" | 22 | #include "swaybar/ipc.h" |
24 | #include "swaybar/status_line.h" | 23 | #include "swaybar/status_line.h" |
@@ -26,15 +25,28 @@ | |||
26 | #include "ipc-client.h" | 25 | #include "ipc-client.h" |
27 | #include "list.h" | 26 | #include "list.h" |
28 | #include "log.h" | 27 | #include "log.h" |
28 | #include "loop.h" | ||
29 | #include "pool-buffer.h" | 29 | #include "pool-buffer.h" |
30 | #include "wlr-layer-shell-unstable-v1-client-protocol.h" | 30 | #include "wlr-layer-shell-unstable-v1-client-protocol.h" |
31 | #include "xdg-output-unstable-v1-client-protocol.h" | 31 | #include "xdg-output-unstable-v1-client-protocol.h" |
32 | 32 | ||
33 | static void bar_init(struct swaybar *bar) { | 33 | static void bar_init(struct swaybar *bar) { |
34 | bar->config = init_config(); | 34 | bar->config = init_config(); |
35 | bar->visible = true; | ||
35 | wl_list_init(&bar->outputs); | 36 | wl_list_init(&bar->outputs); |
36 | } | 37 | } |
37 | 38 | ||
39 | void free_hotspots(struct wl_list *list) { | ||
40 | struct swaybar_hotspot *hotspot, *tmp; | ||
41 | wl_list_for_each_safe(hotspot, tmp, list, link) { | ||
42 | wl_list_remove(&hotspot->link); | ||
43 | if (hotspot->destroy) { | ||
44 | hotspot->destroy(hotspot->data); | ||
45 | } | ||
46 | free(hotspot); | ||
47 | } | ||
48 | } | ||
49 | |||
38 | void free_workspaces(struct wl_list *list) { | 50 | void free_workspaces(struct wl_list *list) { |
39 | struct swaybar_workspace *ws, *tmp; | 51 | struct swaybar_workspace *ws, *tmp; |
40 | wl_list_for_each_safe(ws, tmp, list, link) { | 52 | wl_list_for_each_safe(ws, tmp, list, link) { |
@@ -59,14 +71,8 @@ static void swaybar_output_free(struct swaybar_output *output) { | |||
59 | wl_output_destroy(output->output); | 71 | wl_output_destroy(output->output); |
60 | destroy_buffer(&output->buffers[0]); | 72 | destroy_buffer(&output->buffers[0]); |
61 | destroy_buffer(&output->buffers[1]); | 73 | destroy_buffer(&output->buffers[1]); |
74 | free_hotspots(&output->hotspots); | ||
62 | free_workspaces(&output->workspaces); | 75 | free_workspaces(&output->workspaces); |
63 | struct swaybar_hotspot *hotspot, *hotspot_tmp; | ||
64 | wl_list_for_each_safe(hotspot, hotspot_tmp, &output->hotspots, link) { | ||
65 | if (hotspot->destroy) { | ||
66 | hotspot->destroy(hotspot->data); | ||
67 | } | ||
68 | free(hotspot); | ||
69 | } | ||
70 | wl_list_remove(&output->link); | 76 | wl_list_remove(&output->link); |
71 | free(output->name); | 77 | free(output->name); |
72 | free(output); | 78 | free(output); |
@@ -75,9 +81,7 @@ static void swaybar_output_free(struct swaybar_output *output) { | |||
75 | static void set_output_dirty(struct swaybar_output *output) { | 81 | static void set_output_dirty(struct swaybar_output *output) { |
76 | if (output->frame_scheduled) { | 82 | if (output->frame_scheduled) { |
77 | output->dirty = true; | 83 | output->dirty = true; |
78 | return; | 84 | } else if (output->surface) { |
79 | } | ||
80 | if (output->surface) { | ||
81 | render_frame(output); | 85 | render_frame(output); |
82 | } | 86 | } |
83 | } | 87 | } |
@@ -335,21 +339,68 @@ const struct wl_seat_listener seat_listener = { | |||
335 | }; | 339 | }; |
336 | 340 | ||
337 | static void add_layer_surface(struct swaybar_output *output) { | 341 | static void add_layer_surface(struct swaybar_output *output) { |
338 | if (output->surface != NULL) { | 342 | if (output->layer_surface) { |
339 | return; | 343 | return; |
340 | } | 344 | } |
341 | struct swaybar *bar = output->bar; | 345 | struct swaybar *bar = output->bar; |
342 | 346 | ||
343 | output->surface = wl_compositor_create_surface(bar->compositor); | 347 | struct swaybar_config *config = bar->config; |
344 | assert(output->surface); | 348 | bool hidden = strcmp(config->mode, "hide") == 0; |
345 | output->layer_surface = zwlr_layer_shell_v1_get_layer_surface( | 349 | output->layer_surface = zwlr_layer_shell_v1_get_layer_surface( |
346 | bar->layer_shell, output->surface, output->output, | 350 | bar->layer_shell, output->surface, output->output, |
351 | hidden ? ZWLR_LAYER_SHELL_V1_LAYER_TOP : | ||
347 | ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "panel"); | 352 | ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "panel"); |
348 | assert(output->layer_surface); | 353 | assert(output->layer_surface); |
349 | zwlr_layer_surface_v1_add_listener(output->layer_surface, | 354 | zwlr_layer_surface_v1_add_listener(output->layer_surface, |
350 | &layer_surface_listener, output); | 355 | &layer_surface_listener, output); |
351 | zwlr_layer_surface_v1_set_anchor(output->layer_surface, | 356 | |
352 | bar->config->position); | 357 | zwlr_layer_surface_v1_set_anchor(output->layer_surface, config->position); |
358 | if (hidden) { | ||
359 | zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, -1); | ||
360 | } | ||
361 | } | ||
362 | |||
363 | static void destroy_layer_surface(struct swaybar_output *output) { | ||
364 | if (!output->layer_surface) { | ||
365 | return; | ||
366 | } | ||
367 | zwlr_layer_surface_v1_destroy(output->layer_surface); | ||
368 | wl_surface_attach(output->surface, NULL, 0, 0); // detach buffer | ||
369 | output->layer_surface = NULL; | ||
370 | output->width = 0; | ||
371 | output->frame_scheduled = false; | ||
372 | } | ||
373 | |||
374 | bool determine_bar_visibility(struct swaybar *bar, bool moving_layer) { | ||
375 | struct swaybar_config *config = bar->config; | ||
376 | bool visible = !(strcmp(config->mode, "invisible") == 0 || | ||
377 | (strcmp(config->mode, config->hidden_state) == 0 // both "hide" | ||
378 | && !bar->visible_by_modifier && !bar->visible_by_urgency)); | ||
379 | |||
380 | struct swaybar_output *output; | ||
381 | if (visible == bar->visible) { | ||
382 | if (visible && moving_layer) { | ||
383 | // need to destroy layer surface to move to a different layer | ||
384 | wl_list_for_each(output, &bar->outputs, link) { | ||
385 | destroy_layer_surface(output); | ||
386 | add_layer_surface(output); | ||
387 | } | ||
388 | } | ||
389 | } else { | ||
390 | bar->visible = visible; | ||
391 | wl_list_for_each(output, &bar->outputs, link) { | ||
392 | if (visible) { | ||
393 | add_layer_surface(output); | ||
394 | } else { | ||
395 | destroy_layer_surface(output); | ||
396 | } | ||
397 | } | ||
398 | wlr_log(WLR_DEBUG, "Sending %s signal to status command", | ||
399 | visible ? "cont" : "stop"); | ||
400 | kill(bar->status->pid, | ||
401 | visible ? bar->status->cont_signal : bar->status->stop_signal); | ||
402 | } | ||
403 | return visible; | ||
353 | } | 404 | } |
354 | 405 | ||
355 | static bool bar_uses_output(struct swaybar *bar, const char *name) { | 406 | static bool bar_uses_output(struct swaybar *bar, const char *name) { |
@@ -420,8 +471,11 @@ static void xdg_output_handle_done(void *data, | |||
420 | wl_list_remove(&output->link); | 471 | wl_list_remove(&output->link); |
421 | wl_list_insert(&bar->outputs, &output->link); | 472 | wl_list_insert(&bar->outputs, &output->link); |
422 | 473 | ||
423 | add_layer_surface(output); | 474 | output->surface = wl_compositor_create_surface(bar->compositor); |
424 | set_output_dirty(output); | 475 | assert(output->surface); |
476 | if (bar->visible) { | ||
477 | add_layer_surface(output); | ||
478 | } | ||
425 | } | 479 | } |
426 | } | 480 | } |
427 | 481 | ||
@@ -517,22 +571,26 @@ static void set_bar_dirty(struct swaybar *bar) { | |||
517 | } | 571 | } |
518 | } | 572 | } |
519 | 573 | ||
520 | bool bar_setup(struct swaybar *bar, | 574 | bool bar_setup(struct swaybar *bar, const char *socket_path) { |
521 | const char *socket_path, const char *bar_id) { | ||
522 | bar_init(bar); | 575 | bar_init(bar); |
523 | init_event_loop(); | 576 | bar->eventloop = loop_create(); |
524 | 577 | ||
525 | bar->ipc_socketfd = ipc_open_socket(socket_path); | 578 | bar->ipc_socketfd = ipc_open_socket(socket_path); |
526 | bar->ipc_event_socketfd = ipc_open_socket(socket_path); | 579 | bar->ipc_event_socketfd = ipc_open_socket(socket_path); |
527 | if (!ipc_initialize(bar, bar_id)) { | 580 | if (!ipc_initialize(bar)) { |
528 | return false; | 581 | return false; |
529 | } | 582 | } |
530 | if (bar->config->status_command) { | 583 | if (bar->config->status_command) { |
531 | bar->status = status_line_init(bar->config->status_command); | 584 | bar->status = status_line_init(bar->config->status_command); |
585 | bar->status->bar = bar; | ||
532 | } | 586 | } |
533 | 587 | ||
534 | bar->display = wl_display_connect(NULL); | 588 | bar->display = wl_display_connect(NULL); |
535 | assert(bar->display); | 589 | if (!bar->display) { |
590 | sway_abort("Unable to connect to the compositor. " | ||
591 | "If your compositor is running, check or set the " | ||
592 | "WAYLAND_DISPLAY environment variable."); | ||
593 | } | ||
536 | 594 | ||
537 | struct wl_registry *registry = wl_display_get_registry(bar->display); | 595 | struct wl_registry *registry = wl_display_get_registry(bar->display); |
538 | wl_registry_add_listener(registry, ®istry_listener, bar); | 596 | wl_registry_add_listener(registry, ®istry_listener, bar); |
@@ -565,8 +623,11 @@ bool bar_setup(struct swaybar *bar, | |||
565 | pointer->cursor_surface = wl_compositor_create_surface(bar->compositor); | 623 | pointer->cursor_surface = wl_compositor_create_surface(bar->compositor); |
566 | assert(pointer->cursor_surface); | 624 | assert(pointer->cursor_surface); |
567 | 625 | ||
568 | ipc_get_workspaces(bar); | 626 | if (bar->config->workspace_buttons) { |
569 | set_bar_dirty(bar); | 627 | if (ipc_get_workspaces(bar)) { |
628 | set_bar_dirty(bar); | ||
629 | } | ||
630 | } | ||
570 | return true; | 631 | return true; |
571 | } | 632 | } |
572 | 633 | ||
@@ -590,21 +651,23 @@ static void status_in(int fd, short mask, void *data) { | |||
590 | if (mask & (POLLHUP | POLLERR)) { | 651 | if (mask & (POLLHUP | POLLERR)) { |
591 | status_error(bar->status, "[error reading from status command]"); | 652 | status_error(bar->status, "[error reading from status command]"); |
592 | set_bar_dirty(bar); | 653 | set_bar_dirty(bar); |
593 | remove_event(fd); | 654 | loop_remove_fd(bar->eventloop, fd); |
594 | } else if (status_handle_readable(bar->status)) { | 655 | } else if (status_handle_readable(bar->status)) { |
595 | set_bar_dirty(bar); | 656 | set_bar_dirty(bar); |
596 | } | 657 | } |
597 | } | 658 | } |
598 | 659 | ||
599 | void bar_run(struct swaybar *bar) { | 660 | void bar_run(struct swaybar *bar) { |
600 | add_event(wl_display_get_fd(bar->display), POLLIN, display_in, bar); | 661 | loop_add_fd(bar->eventloop, wl_display_get_fd(bar->display), POLLIN, |
601 | add_event(bar->ipc_event_socketfd, POLLIN, ipc_in, bar); | 662 | display_in, bar); |
663 | loop_add_fd(bar->eventloop, bar->ipc_event_socketfd, POLLIN, ipc_in, bar); | ||
602 | if (bar->status) { | 664 | if (bar->status) { |
603 | add_event(bar->status->read_fd, POLLIN, status_in, bar); | 665 | loop_add_fd(bar->eventloop, bar->status->read_fd, POLLIN, |
666 | status_in, bar); | ||
604 | } | 667 | } |
605 | while (1) { | 668 | while (1) { |
606 | wl_display_flush(bar->display); | 669 | wl_display_flush(bar->display); |
607 | event_loop_poll(); | 670 | loop_poll(bar->eventloop); |
608 | } | 671 | } |
609 | } | 672 | } |
610 | 673 | ||
@@ -625,4 +688,6 @@ void bar_teardown(struct swaybar *bar) { | |||
625 | if (bar->status) { | 688 | if (bar->status) { |
626 | status_line_free(bar->status); | 689 | status_line_free(bar->status); |
627 | } | 690 | } |
691 | free(bar->id); | ||
692 | free(bar->mode); | ||
628 | } | 693 | } |
diff --git a/swaybar/config.c b/swaybar/config.c index 09d40c24..eafb0b69 100644 --- a/swaybar/config.c +++ b/swaybar/config.c | |||
@@ -30,7 +30,8 @@ struct swaybar_config *init_config(void) { | |||
30 | config->pango_markup = false; | 30 | config->pango_markup = false; |
31 | config->position = parse_position("bottom"); | 31 | config->position = parse_position("bottom"); |
32 | config->font = strdup("monospace 10"); | 32 | config->font = strdup("monospace 10"); |
33 | config->mode = NULL; | 33 | config->mode = strdup("dock"); |
34 | config->hidden_state = strdup("hide"); | ||
34 | config->sep_symbol = NULL; | 35 | config->sep_symbol = NULL; |
35 | config->strip_workspace_numbers = false; | 36 | config->strip_workspace_numbers = false; |
36 | config->binding_mode_indicator = true; | 37 | config->binding_mode_indicator = true; |
@@ -84,6 +85,7 @@ void free_config(struct swaybar_config *config) { | |||
84 | free(config->status_command); | 85 | free(config->status_command); |
85 | free(config->font); | 86 | free(config->font); |
86 | free(config->mode); | 87 | free(config->mode); |
88 | free(config->hidden_state); | ||
87 | free(config->sep_symbol); | 89 | free(config->sep_symbol); |
88 | for (int i = 0; i < config->bindings->length; i++) { | 90 | for (int i = 0; i < config->bindings->length; i++) { |
89 | struct swaybar_binding *binding = config->bindings->items[i]; | 91 | struct swaybar_binding *binding = config->bindings->items[i]; |
diff --git a/swaybar/event_loop.c b/swaybar/event_loop.c deleted file mode 100644 index 686b9962..00000000 --- a/swaybar/event_loop.c +++ /dev/null | |||
@@ -1,156 +0,0 @@ | |||
1 | #define _XOPEN_SOURCE 700 | ||
2 | #include <stdlib.h> | ||
3 | #include <stdbool.h> | ||
4 | #include <string.h> | ||
5 | #include <strings.h> | ||
6 | #include <poll.h> | ||
7 | #include <time.h> | ||
8 | #include "swaybar/event_loop.h" | ||
9 | #include "list.h" | ||
10 | |||
11 | struct event_item { | ||
12 | void (*cb)(int fd, short mask, void *data); | ||
13 | void *data; | ||
14 | }; | ||
15 | |||
16 | struct timer_item { | ||
17 | timer_t timer; | ||
18 | void (*cb)(timer_t timer, void *data); | ||
19 | void *data; | ||
20 | }; | ||
21 | |||
22 | static struct { | ||
23 | // The order of each must be kept consistent | ||
24 | struct { /* pollfd array */ | ||
25 | struct pollfd *items; | ||
26 | int capacity; | ||
27 | int length; | ||
28 | } fds; | ||
29 | list_t *items; /* event_item list */ | ||
30 | |||
31 | // Timer list | ||
32 | list_t *timers; | ||
33 | } event_loop; | ||
34 | |||
35 | void add_timer(timer_t timer, | ||
36 | void(*cb)(timer_t timer, void *data), | ||
37 | void *data) { | ||
38 | |||
39 | struct timer_item *item = malloc(sizeof(struct timer_item)); | ||
40 | item->timer = timer; | ||
41 | item->cb = cb; | ||
42 | item->data = data; | ||
43 | |||
44 | list_add(event_loop.timers, item); | ||
45 | } | ||
46 | |||
47 | void add_event(int fd, short mask, | ||
48 | void(*cb)(int fd, short mask, void *data), void *data) { | ||
49 | |||
50 | struct pollfd pollfd = { | ||
51 | fd, | ||
52 | mask, | ||
53 | 0, | ||
54 | }; | ||
55 | |||
56 | // Resize | ||
57 | if (event_loop.fds.length == event_loop.fds.capacity) { | ||
58 | event_loop.fds.capacity += 10; | ||
59 | event_loop.fds.items = realloc(event_loop.fds.items, | ||
60 | sizeof(struct pollfd) * event_loop.fds.capacity); | ||
61 | } | ||
62 | |||
63 | event_loop.fds.items[event_loop.fds.length++] = pollfd; | ||
64 | |||
65 | struct event_item *item = malloc(sizeof(struct event_item)); | ||
66 | item->cb = cb; | ||
67 | item->data = data; | ||
68 | |||
69 | list_add(event_loop.items, item); | ||
70 | |||
71 | return; | ||
72 | } | ||
73 | |||
74 | bool remove_event(int fd) { | ||
75 | /* | ||
76 | * Instead of removing events immediately, we mark them for deletion | ||
77 | * and clean them up later. This is so we can call remove_event inside | ||
78 | * an event callback safely. | ||
79 | */ | ||
80 | for (int i = 0; i < event_loop.fds.length; ++i) { | ||
81 | if (event_loop.fds.items[i].fd == fd) { | ||
82 | event_loop.fds.items[i].fd = -1; | ||
83 | return true; | ||
84 | } | ||
85 | } | ||
86 | return false; | ||
87 | } | ||
88 | |||
89 | static int timer_item_timer_cmp(const void *_timer_item, const void *_timer) { | ||
90 | const struct timer_item *timer_item = _timer_item; | ||
91 | const timer_t *timer = _timer; | ||
92 | if (timer_item->timer == *timer) { | ||
93 | return 0; | ||
94 | } else { | ||
95 | return -1; | ||
96 | } | ||
97 | } | ||
98 | bool remove_timer(timer_t timer) { | ||
99 | int index = list_seq_find(event_loop.timers, timer_item_timer_cmp, &timer); | ||
100 | if (index != -1) { | ||
101 | free(event_loop.timers->items[index]); | ||
102 | list_del(event_loop.timers, index); | ||
103 | return true; | ||
104 | } | ||
105 | return false; | ||
106 | } | ||
107 | |||
108 | void event_loop_poll(void) { | ||
109 | poll(event_loop.fds.items, event_loop.fds.length, -1); | ||
110 | |||
111 | for (int i = 0; i < event_loop.fds.length; ++i) { | ||
112 | struct pollfd pfd = event_loop.fds.items[i]; | ||
113 | struct event_item *item = (struct event_item *)event_loop.items->items[i]; | ||
114 | |||
115 | // Always send these events | ||
116 | unsigned events = pfd.events | POLLHUP | POLLERR; | ||
117 | |||
118 | if (pfd.revents & events) { | ||
119 | item->cb(pfd.fd, pfd.revents, item->data); | ||
120 | } | ||
121 | } | ||
122 | |||
123 | // Cleanup removed events | ||
124 | int end = 0; | ||
125 | int length = event_loop.fds.length; | ||
126 | for (int i = 0; i < length; ++i) { | ||
127 | if (event_loop.fds.items[i].fd == -1) { | ||
128 | free(event_loop.items->items[i]); | ||
129 | list_del(event_loop.items, i); | ||
130 | --event_loop.fds.length; | ||
131 | } else if (end != i) { | ||
132 | event_loop.fds.items[end++] = event_loop.fds.items[i]; | ||
133 | } else { | ||
134 | end = i + 1; | ||
135 | } | ||
136 | } | ||
137 | |||
138 | // check timers | ||
139 | // not tested, but seems to work | ||
140 | for (int i = 0; i < event_loop.timers->length; ++i) { | ||
141 | struct timer_item *item = event_loop.timers->items[i]; | ||
142 | int overrun = timer_getoverrun(item->timer); | ||
143 | if (overrun && overrun != -1) { | ||
144 | item->cb(item->timer, item->data); | ||
145 | } | ||
146 | } | ||
147 | } | ||
148 | |||
149 | void init_event_loop(void) { | ||
150 | event_loop.fds.length = 0; | ||
151 | event_loop.fds.capacity = 10; | ||
152 | event_loop.fds.items = malloc( | ||
153 | event_loop.fds.capacity * sizeof(struct pollfd)); | ||
154 | event_loop.items = create_list(); | ||
155 | event_loop.timers = create_list(); | ||
156 | } | ||
diff --git a/swaybar/ipc.c b/swaybar/ipc.c index a67814c1..e1b30b52 100644 --- a/swaybar/ipc.c +++ b/swaybar/ipc.c | |||
@@ -152,12 +152,12 @@ static bool ipc_parse_config( | |||
152 | json_object_put(bar_config); | 152 | json_object_put(bar_config); |
153 | return false; | 153 | return false; |
154 | } | 154 | } |
155 | json_object *markup, *mode, *hidden_bar, *position, *status_command; | 155 | json_object *markup, *mode, *hidden_state, *position, *status_command; |
156 | json_object *font, *bar_height, *wrap_scroll, *workspace_buttons, *strip_workspace_numbers; | 156 | json_object *font, *bar_height, *wrap_scroll, *workspace_buttons, *strip_workspace_numbers; |
157 | json_object *binding_mode_indicator, *verbose, *colors, *sep_symbol, *outputs; | 157 | json_object *binding_mode_indicator, *verbose, *colors, *sep_symbol, *outputs; |
158 | json_object *bindings; | 158 | json_object *bindings; |
159 | json_object_object_get_ex(bar_config, "mode", &mode); | 159 | json_object_object_get_ex(bar_config, "mode", &mode); |
160 | json_object_object_get_ex(bar_config, "hidden_bar", &hidden_bar); | 160 | json_object_object_get_ex(bar_config, "hidden_state", &hidden_state); |
161 | json_object_object_get_ex(bar_config, "position", &position); | 161 | json_object_object_get_ex(bar_config, "position", &position); |
162 | json_object_object_get_ex(bar_config, "status_command", &status_command); | 162 | json_object_object_get_ex(bar_config, "status_command", &status_command); |
163 | json_object_object_get_ex(bar_config, "font", &font); | 163 | json_object_object_get_ex(bar_config, "font", &font); |
@@ -220,6 +220,14 @@ static bool ipc_parse_config( | |||
220 | list_add(config->bindings, binding); | 220 | list_add(config->bindings, binding); |
221 | } | 221 | } |
222 | } | 222 | } |
223 | if (hidden_state) { | ||
224 | free(config->hidden_state); | ||
225 | config->hidden_state = strdup(json_object_get_string(hidden_state)); | ||
226 | } | ||
227 | if (mode) { | ||
228 | free(config->mode); | ||
229 | config->mode = strdup(json_object_get_string(mode)); | ||
230 | } | ||
223 | 231 | ||
224 | struct config_output *output, *tmp; | 232 | struct config_output *output, *tmp; |
225 | wl_list_for_each_safe(output, tmp, &config->outputs, link) { | 233 | wl_list_for_each_safe(output, tmp, &config->outputs, link) { |
@@ -254,7 +262,7 @@ static bool ipc_parse_config( | |||
254 | return true; | 262 | return true; |
255 | } | 263 | } |
256 | 264 | ||
257 | void ipc_get_workspaces(struct swaybar *bar) { | 265 | bool ipc_get_workspaces(struct swaybar *bar) { |
258 | struct swaybar_output *output; | 266 | struct swaybar_output *output; |
259 | wl_list_for_each(output, &bar->outputs, link) { | 267 | wl_list_for_each(output, &bar->outputs, link) { |
260 | free_workspaces(&output->workspaces); | 268 | free_workspaces(&output->workspaces); |
@@ -266,8 +274,10 @@ void ipc_get_workspaces(struct swaybar *bar) { | |||
266 | json_object *results = json_tokener_parse(res); | 274 | json_object *results = json_tokener_parse(res); |
267 | if (!results) { | 275 | if (!results) { |
268 | free(res); | 276 | free(res); |
269 | return; | 277 | return false; |
270 | } | 278 | } |
279 | |||
280 | bar->visible_by_urgency = false; | ||
271 | size_t length = json_object_array_length(results); | 281 | size_t length = json_object_array_length(results); |
272 | json_object *ws_json; | 282 | json_object *ws_json; |
273 | json_object *num, *name, *visible, *focused, *out, *urgent; | 283 | json_object *num, *name, *visible, *focused, *out, *urgent; |
@@ -294,12 +304,16 @@ void ipc_get_workspaces(struct swaybar *bar) { | |||
294 | output->focused = true; | 304 | output->focused = true; |
295 | } | 305 | } |
296 | ws->urgent = json_object_get_boolean(urgent); | 306 | ws->urgent = json_object_get_boolean(urgent); |
307 | if (ws->urgent) { | ||
308 | bar->visible_by_urgency = true; | ||
309 | } | ||
297 | wl_list_insert(&output->workspaces, &ws->link); | 310 | wl_list_insert(&output->workspaces, &ws->link); |
298 | } | 311 | } |
299 | } | 312 | } |
300 | } | 313 | } |
301 | json_object_put(results); | 314 | json_object_put(results); |
302 | free(res); | 315 | free(res); |
316 | return determine_bar_visibility(bar, false); | ||
303 | } | 317 | } |
304 | 318 | ||
305 | static void ipc_get_outputs(struct swaybar *bar) { | 319 | static void ipc_get_outputs(struct swaybar *bar) { |
@@ -345,10 +359,10 @@ void ipc_execute_binding(struct swaybar *bar, struct swaybar_binding *bind) { | |||
345 | IPC_COMMAND, bind->command, &len)); | 359 | IPC_COMMAND, bind->command, &len)); |
346 | } | 360 | } |
347 | 361 | ||
348 | bool ipc_initialize(struct swaybar *bar, const char *bar_id) { | 362 | bool ipc_initialize(struct swaybar *bar) { |
349 | uint32_t len = strlen(bar_id); | 363 | uint32_t len = strlen(bar->id); |
350 | char *res = ipc_single_command(bar->ipc_socketfd, | 364 | char *res = ipc_single_command(bar->ipc_socketfd, |
351 | IPC_GET_BAR_CONFIG, bar_id, &len); | 365 | IPC_GET_BAR_CONFIG, bar->id, &len); |
352 | if (!ipc_parse_config(bar->config, res)) { | 366 | if (!ipc_parse_config(bar->config, res)) { |
353 | free(res); | 367 | free(res); |
354 | return false; | 368 | return false; |
@@ -356,56 +370,108 @@ bool ipc_initialize(struct swaybar *bar, const char *bar_id) { | |||
356 | free(res); | 370 | free(res); |
357 | ipc_get_outputs(bar); | 371 | ipc_get_outputs(bar); |
358 | 372 | ||
359 | const char *subscribe = "[ \"workspace\", \"mode\" ]"; | 373 | struct swaybar_config *config = bar->config; |
360 | len = strlen(subscribe); | 374 | char subscribe[128]; // suitably large buffer |
375 | len = snprintf(subscribe, 128, | ||
376 | "[ \"barconfig_update\" , \"bar_state_update\" %s %s ]", | ||
377 | config->binding_mode_indicator ? ", \"mode\"" : "", | ||
378 | config->workspace_buttons ? ", \"workspace\"" : ""); | ||
361 | free(ipc_single_command(bar->ipc_event_socketfd, | 379 | free(ipc_single_command(bar->ipc_event_socketfd, |
362 | IPC_SUBSCRIBE, subscribe, &len)); | 380 | IPC_SUBSCRIBE, subscribe, &len)); |
363 | return true; | 381 | return true; |
364 | } | 382 | } |
365 | 383 | ||
384 | static bool handle_bar_state_update(struct swaybar *bar, json_object *event) { | ||
385 | json_object *json_id; | ||
386 | json_object_object_get_ex(event, "id", &json_id); | ||
387 | const char *id = json_object_get_string(json_id); | ||
388 | if (strcmp(id, bar->id) != 0) { | ||
389 | return false; | ||
390 | } | ||
391 | |||
392 | json_object *visible_by_modifier; | ||
393 | json_object_object_get_ex(event, "visible_by_modifier", &visible_by_modifier); | ||
394 | bar->visible_by_modifier = json_object_get_boolean(visible_by_modifier); | ||
395 | return determine_bar_visibility(bar, false); | ||
396 | } | ||
397 | |||
398 | static bool handle_barconfig_update(struct swaybar *bar, | ||
399 | json_object *json_config) { | ||
400 | json_object *json_id; | ||
401 | json_object_object_get_ex(json_config, "id", &json_id); | ||
402 | const char *id = json_object_get_string(json_id); | ||
403 | if (strcmp(id, bar->id) != 0) { | ||
404 | return false; | ||
405 | } | ||
406 | |||
407 | struct swaybar_config *config = bar->config; | ||
408 | |||
409 | json_object *json_state; | ||
410 | json_object_object_get_ex(json_config, "hidden_state", &json_state); | ||
411 | const char *new_state = json_object_get_string(json_state); | ||
412 | char *old_state = config->hidden_state; | ||
413 | if (strcmp(new_state, old_state) != 0) { | ||
414 | wlr_log(WLR_DEBUG, "Changing bar hidden state to %s", new_state); | ||
415 | free(old_state); | ||
416 | config->hidden_state = strdup(new_state); | ||
417 | return determine_bar_visibility(bar, false); | ||
418 | } | ||
419 | |||
420 | free(config->mode); | ||
421 | json_object *json_mode; | ||
422 | json_object_object_get_ex(json_config, "mode", &json_mode); | ||
423 | config->mode = strdup(json_object_get_string(json_mode)); | ||
424 | wlr_log(WLR_DEBUG, "Changing bar mode to %s", config->mode); | ||
425 | |||
426 | return determine_bar_visibility(bar, true); | ||
427 | } | ||
428 | |||
366 | bool handle_ipc_readable(struct swaybar *bar) { | 429 | bool handle_ipc_readable(struct swaybar *bar) { |
367 | struct ipc_response *resp = ipc_recv_response(bar->ipc_event_socketfd); | 430 | struct ipc_response *resp = ipc_recv_response(bar->ipc_event_socketfd); |
368 | if (!resp) { | 431 | if (!resp) { |
369 | return false; | 432 | return false; |
370 | } | 433 | } |
434 | |||
435 | json_object *result = json_tokener_parse(resp->payload); | ||
436 | if (!result) { | ||
437 | wlr_log(WLR_ERROR, "failed to parse payload as json"); | ||
438 | free_ipc_response(resp); | ||
439 | return false; | ||
440 | } | ||
441 | |||
442 | bool bar_is_dirty = true; | ||
371 | switch (resp->type) { | 443 | switch (resp->type) { |
372 | case IPC_EVENT_WORKSPACE: | 444 | case IPC_EVENT_WORKSPACE: |
373 | ipc_get_workspaces(bar); | 445 | bar_is_dirty = ipc_get_workspaces(bar); |
374 | break; | 446 | break; |
375 | case IPC_EVENT_MODE: { | 447 | case IPC_EVENT_MODE: { |
376 | json_object *result = json_tokener_parse(resp->payload); | ||
377 | if (!result) { | ||
378 | free_ipc_response(resp); | ||
379 | wlr_log(WLR_ERROR, "failed to parse payload as json"); | ||
380 | return false; | ||
381 | } | ||
382 | json_object *json_change, *json_pango_markup; | 448 | json_object *json_change, *json_pango_markup; |
383 | if (json_object_object_get_ex(result, "change", &json_change)) { | 449 | if (json_object_object_get_ex(result, "change", &json_change)) { |
384 | const char *change = json_object_get_string(json_change); | 450 | const char *change = json_object_get_string(json_change); |
385 | free(bar->config->mode); | 451 | free(bar->mode); |
386 | if (strcmp(change, "default") == 0) { | 452 | bar->mode = strcmp(change, "default") != 0 ? strdup(change) : NULL; |
387 | bar->config->mode = NULL; | ||
388 | } else { | ||
389 | bar->config->mode = strdup(change); | ||
390 | } | ||
391 | } else { | 453 | } else { |
392 | wlr_log(WLR_ERROR, "failed to parse response"); | 454 | wlr_log(WLR_ERROR, "failed to parse response"); |
393 | json_object_put(result); | 455 | bar_is_dirty = false; |
394 | free_ipc_response(resp); | 456 | break; |
395 | return false; | ||
396 | } | 457 | } |
397 | if (json_object_object_get_ex(result, | 458 | if (json_object_object_get_ex(result, |
398 | "pango_markup", &json_pango_markup)) { | 459 | "pango_markup", &json_pango_markup)) { |
399 | bar->config->mode_pango_markup = json_object_get_boolean( | 460 | bar->mode_pango_markup = json_object_get_boolean(json_pango_markup); |
400 | json_pango_markup); | ||
401 | } | 461 | } |
402 | json_object_put(result); | ||
403 | break; | 462 | break; |
404 | } | 463 | } |
464 | case IPC_EVENT_BARCONFIG_UPDATE: | ||
465 | bar_is_dirty = handle_barconfig_update(bar, result); | ||
466 | break; | ||
467 | case IPC_EVENT_BAR_STATE_UPDATE: | ||
468 | bar_is_dirty = handle_bar_state_update(bar, result); | ||
469 | break; | ||
405 | default: | 470 | default: |
406 | free_ipc_response(resp); | 471 | bar_is_dirty = false; |
407 | return false; | 472 | break; |
408 | } | 473 | } |
474 | json_object_put(result); | ||
409 | free_ipc_response(resp); | 475 | free_ipc_response(resp); |
410 | return true; | 476 | return bar_is_dirty; |
411 | } | 477 | } |
diff --git a/swaybar/main.c b/swaybar/main.c index db204f4a..2672abef 100644 --- a/swaybar/main.c +++ b/swaybar/main.c | |||
@@ -22,7 +22,6 @@ void sway_terminate(int code) { | |||
22 | 22 | ||
23 | int main(int argc, char **argv) { | 23 | int main(int argc, char **argv) { |
24 | char *socket_path = NULL; | 24 | char *socket_path = NULL; |
25 | char *bar_id = NULL; | ||
26 | bool debug = false; | 25 | bool debug = false; |
27 | 26 | ||
28 | static struct option long_options[] = { | 27 | static struct option long_options[] = { |
@@ -59,7 +58,7 @@ int main(int argc, char **argv) { | |||
59 | socket_path = strdup(optarg); | 58 | socket_path = strdup(optarg); |
60 | break; | 59 | break; |
61 | case 'b': // Type | 60 | case 'b': // Type |
62 | bar_id = strdup(optarg); | 61 | swaybar.id = strdup(optarg); |
63 | break; | 62 | break; |
64 | case 'v': | 63 | case 'v': |
65 | fprintf(stdout, "swaybar version " SWAY_VERSION "\n"); | 64 | fprintf(stdout, "swaybar version " SWAY_VERSION "\n"); |
@@ -80,7 +79,7 @@ int main(int argc, char **argv) { | |||
80 | wlr_log_init(WLR_ERROR, NULL); | 79 | wlr_log_init(WLR_ERROR, NULL); |
81 | } | 80 | } |
82 | 81 | ||
83 | if (!bar_id) { | 82 | if (!swaybar.id) { |
84 | wlr_log(WLR_ERROR, "No bar_id passed. " | 83 | wlr_log(WLR_ERROR, "No bar_id passed. " |
85 | "Provide --bar_id or let sway start swaybar"); | 84 | "Provide --bar_id or let sway start swaybar"); |
86 | return 1; | 85 | return 1; |
@@ -96,13 +95,12 @@ int main(int argc, char **argv) { | |||
96 | 95 | ||
97 | signal(SIGTERM, sig_handler); | 96 | signal(SIGTERM, sig_handler); |
98 | 97 | ||
99 | if (!bar_setup(&swaybar, socket_path, bar_id)) { | 98 | if (!bar_setup(&swaybar, socket_path)) { |
100 | free(socket_path); | 99 | free(socket_path); |
101 | return 1; | 100 | return 1; |
102 | } | 101 | } |
103 | 102 | ||
104 | free(socket_path); | 103 | free(socket_path); |
105 | free(bar_id); | ||
106 | 104 | ||
107 | bar_run(&swaybar); | 105 | bar_run(&swaybar); |
108 | bar_teardown(&swaybar); | 106 | bar_teardown(&swaybar); |
diff --git a/swaybar/meson.build b/swaybar/meson.build index 7a02a33f..0c116172 100644 --- a/swaybar/meson.build +++ b/swaybar/meson.build | |||
@@ -2,7 +2,6 @@ executable( | |||
2 | 'swaybar', [ | 2 | 'swaybar', [ |
3 | 'bar.c', | 3 | 'bar.c', |
4 | 'config.c', | 4 | 'config.c', |
5 | 'event_loop.c', | ||
6 | 'i3bar.c', | 5 | 'i3bar.c', |
7 | 'ipc.c', | 6 | 'ipc.c', |
8 | 'main.c', | 7 | 'main.c', |
diff --git a/swaybar/render.c b/swaybar/render.c index dc31a5ea..097eb462 100644 --- a/swaybar/render.c +++ b/swaybar/render.c | |||
@@ -296,11 +296,15 @@ static uint32_t render_status_line(cairo_t *cairo, | |||
296 | 296 | ||
297 | static uint32_t render_binding_mode_indicator(cairo_t *cairo, | 297 | static uint32_t render_binding_mode_indicator(cairo_t *cairo, |
298 | struct swaybar_output *output, double x) { | 298 | struct swaybar_output *output, double x) { |
299 | const char *mode = output->bar->mode; | ||
300 | if (!mode) { | ||
301 | return 0; | ||
302 | } | ||
303 | |||
299 | struct swaybar_config *config = output->bar->config; | 304 | struct swaybar_config *config = output->bar->config; |
300 | const char *mode = config->mode; | ||
301 | int text_width, text_height; | 305 | int text_width, text_height; |
302 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, | 306 | get_text_size(cairo, config->font, &text_width, &text_height, NULL, |
303 | output->scale, config->mode_pango_markup, | 307 | output->scale, output->bar->mode_pango_markup, |
304 | "%s", mode); | 308 | "%s", mode); |
305 | 309 | ||
306 | int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; | 310 | int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale; |
@@ -333,8 +337,8 @@ static uint32_t render_binding_mode_indicator(cairo_t *cairo, | |||
333 | double text_y = height / 2.0 - text_height / 2.0; | 337 | double text_y = height / 2.0 - text_height / 2.0; |
334 | cairo_set_source_u32(cairo, config->colors.binding_mode.text); | 338 | cairo_set_source_u32(cairo, config->colors.binding_mode.text); |
335 | cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y)); | 339 | cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y)); |
336 | pango_printf(cairo, config->font, output->scale, config->mode_pango_markup, | 340 | pango_printf(cairo, config->font, output->scale, |
337 | "%s", mode); | 341 | output->bar->mode_pango_markup, "%s", mode); |
338 | return output->height; | 342 | return output->height; |
339 | } | 343 | } |
340 | 344 | ||
@@ -465,7 +469,7 @@ static uint32_t render_to_cairo(cairo_t *cairo, struct swaybar_output *output) { | |||
465 | max_height = h > max_height ? h : max_height; | 469 | max_height = h > max_height ? h : max_height; |
466 | } | 470 | } |
467 | } | 471 | } |
468 | if (config->binding_mode_indicator && config->mode) { | 472 | if (config->binding_mode_indicator) { |
469 | uint32_t h = render_binding_mode_indicator(cairo, output, x); | 473 | uint32_t h = render_binding_mode_indicator(cairo, output, x); |
470 | max_height = h > max_height ? h : max_height; | 474 | max_height = h > max_height ? h : max_height; |
471 | } | 475 | } |
@@ -490,16 +494,12 @@ static const struct wl_callback_listener output_frame_listener = { | |||
490 | 494 | ||
491 | void render_frame(struct swaybar_output *output) { | 495 | void render_frame(struct swaybar_output *output) { |
492 | assert(output->surface != NULL); | 496 | assert(output->surface != NULL); |
493 | 497 | if (!output->layer_surface) { | |
494 | struct swaybar_hotspot *hotspot, *tmp; | 498 | return; |
495 | wl_list_for_each_safe(hotspot, tmp, &output->hotspots, link) { | ||
496 | if (hotspot->destroy) { | ||
497 | hotspot->destroy(hotspot->data); | ||
498 | } | ||
499 | wl_list_remove(&hotspot->link); | ||
500 | free(hotspot); | ||
501 | } | 499 | } |
502 | 500 | ||
501 | free_hotspots(&output->hotspots); | ||
502 | |||
503 | cairo_surface_t *recorder = cairo_recording_surface_create( | 503 | cairo_surface_t *recorder = cairo_recording_surface_create( |
504 | CAIRO_CONTENT_COLOR_ALPHA, NULL); | 504 | CAIRO_CONTENT_COLOR_ALPHA, NULL); |
505 | cairo_t *cairo = cairo_create(recorder); | 505 | cairo_t *cairo = cairo_create(recorder); |
@@ -519,10 +519,12 @@ void render_frame(struct swaybar_output *output) { | |||
519 | if (config_height >= 0 && height < (uint32_t)config_height) { | 519 | if (config_height >= 0 && height < (uint32_t)config_height) { |
520 | height = config_height; | 520 | height = config_height; |
521 | } | 521 | } |
522 | if (height != output->height) { | 522 | if (height != output->height || output->width == 0) { |
523 | // Reconfigure surface | 523 | // Reconfigure surface |
524 | zwlr_layer_surface_v1_set_size(output->layer_surface, 0, height); | 524 | zwlr_layer_surface_v1_set_size(output->layer_surface, 0, height); |
525 | zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, height); | 525 | if (strcmp(output->bar->config->mode, "dock") == 0) { |
526 | zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, height); | ||
527 | } | ||
526 | // TODO: this could infinite loop if the compositor assigns us a | 528 | // TODO: this could infinite loop if the compositor assigns us a |
527 | // different height than what we asked for | 529 | // different height than what we asked for |
528 | wl_surface_commit(output->surface); | 530 | wl_surface_commit(output->surface); |
diff --git a/swaybar/status_line.c b/swaybar/status_line.c index ed6dc7c8..65d6c052 100644 --- a/swaybar/status_line.c +++ b/swaybar/status_line.c | |||
@@ -7,16 +7,16 @@ | |||
7 | #include <stdio.h> | 7 | #include <stdio.h> |
8 | #include <unistd.h> | 8 | #include <unistd.h> |
9 | #include <wlr/util/log.h> | 9 | #include <wlr/util/log.h> |
10 | #include "loop.h" | ||
10 | #include "swaybar/bar.h" | 11 | #include "swaybar/bar.h" |
11 | #include "swaybar/config.h" | 12 | #include "swaybar/config.h" |
12 | #include "swaybar/i3bar.h" | 13 | #include "swaybar/i3bar.h" |
13 | #include "swaybar/event_loop.h" | ||
14 | #include "swaybar/status_line.h" | 14 | #include "swaybar/status_line.h" |
15 | #include "readline.h" | 15 | #include "readline.h" |
16 | 16 | ||
17 | static void status_line_close_fds(struct status_line *status) { | 17 | static void status_line_close_fds(struct status_line *status) { |
18 | if (status->read_fd != -1) { | 18 | if (status->read_fd != -1) { |
19 | remove_event(status->read_fd); | 19 | loop_remove_fd(status->bar->eventloop, status->read_fd); |
20 | close(status->read_fd); | 20 | close(status->read_fd); |
21 | status->read_fd = -1; | 21 | status->read_fd = -1; |
22 | } | 22 | } |
@@ -83,6 +83,17 @@ bool status_handle_readable(struct status_line *status) { | |||
83 | return true; | 83 | return true; |
84 | } | 84 | } |
85 | } | 85 | } |
86 | |||
87 | json_object *signal; | ||
88 | if (json_object_object_get_ex(header, "stop_signal", &signal)) { | ||
89 | status->stop_signal = json_object_get_int(signal); | ||
90 | wlr_log(WLR_DEBUG, "Setting stop signal to %d", status->stop_signal); | ||
91 | } | ||
92 | if (json_object_object_get_ex(header, "cont_signal", &signal)) { | ||
93 | status->cont_signal = json_object_get_int(signal); | ||
94 | wlr_log(WLR_DEBUG, "Setting cont signal to %d", status->cont_signal); | ||
95 | } | ||
96 | |||
86 | json_object_put(header); | 97 | json_object_put(header); |
87 | 98 | ||
88 | wl_list_init(&status->blocks); | 99 | wl_list_init(&status->blocks); |
@@ -121,6 +132,9 @@ bool status_handle_readable(struct status_line *status) { | |||
121 | 132 | ||
122 | struct status_line *status_line_init(char *cmd) { | 133 | struct status_line *status_line_init(char *cmd) { |
123 | struct status_line *status = calloc(1, sizeof(struct status_line)); | 134 | struct status_line *status = calloc(1, sizeof(struct status_line)); |
135 | status->stop_signal = SIGSTOP; | ||
136 | status->cont_signal = SIGCONT; | ||
137 | |||
124 | status->buffer_size = 8192; | 138 | status->buffer_size = 8192; |
125 | status->buffer = malloc(status->buffer_size); | 139 | status->buffer = malloc(status->buffer_size); |
126 | 140 | ||
diff --git a/swaybg/main.c b/swaybg/main.c index 742669ef..45b7a913 100644 --- a/swaybg/main.c +++ b/swaybg/main.c | |||
@@ -222,7 +222,12 @@ int main(int argc, const char **argv) { | |||
222 | } | 222 | } |
223 | 223 | ||
224 | state.display = wl_display_connect(NULL); | 224 | state.display = wl_display_connect(NULL); |
225 | assert(state.display); | 225 | if (!state.display) { |
226 | wlr_log(WLR_ERROR, "Unable to connect to the compositor. " | ||
227 | "If your compositor is running, check or set the " | ||
228 | "WAYLAND_DISPLAY environment variable."); | ||
229 | return 1; | ||
230 | } | ||
226 | 231 | ||
227 | struct wl_registry *registry = wl_display_get_registry(state.display); | 232 | struct wl_registry *registry = wl_display_get_registry(state.display); |
228 | wl_registry_add_listener(registry, ®istry_listener, &state); | 233 | wl_registry_add_listener(registry, ®istry_listener, &state); |
diff --git a/swayidle/main.c b/swayidle/main.c index 5b6c95a7..93f4c94b 100644 --- a/swayidle/main.c +++ b/swayidle/main.c | |||
@@ -388,7 +388,9 @@ int main(int argc, char *argv[]) { | |||
388 | 388 | ||
389 | state.display = wl_display_connect(NULL); | 389 | state.display = wl_display_connect(NULL); |
390 | if (state.display == NULL) { | 390 | if (state.display == NULL) { |
391 | wlr_log(WLR_ERROR, "Failed to create display"); | 391 | wlr_log(WLR_ERROR, "Unable to connect to the compositor. " |
392 | "If your compositor is running, check or set the " | ||
393 | "WAYLAND_DISPLAY environment variable."); | ||
392 | return -3; | 394 | return -3; |
393 | } | 395 | } |
394 | 396 | ||
diff --git a/swaylock/main.c b/swaylock/main.c index d1384c6f..86dfd577 100644 --- a/swaylock/main.c +++ b/swaylock/main.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include "pool-buffer.h" | 21 | #include "pool-buffer.h" |
22 | #include "cairo.h" | 22 | #include "cairo.h" |
23 | #include "log.h" | 23 | #include "log.h" |
24 | #include "loop.h" | ||
24 | #include "readline.h" | 25 | #include "readline.h" |
25 | #include "stringop.h" | 26 | #include "stringop.h" |
26 | #include "util.h" | 27 | #include "util.h" |
@@ -633,13 +634,9 @@ static int parse_options(int argc, char **argv, struct swaylock_state *state, | |||
633 | } | 634 | } |
634 | break; | 635 | break; |
635 | case 'v': | 636 | case 'v': |
636 | #if defined SWAY_GIT_VERSION && defined SWAY_GIT_BRANCH && defined SWAY_VERSION_DATE | 637 | fprintf(stdout, "swaylock version " SWAY_VERSION "\n"); |
637 | fprintf(stdout, "swaylock version %s (%s, branch \"%s\")\n", | 638 | exit(EXIT_SUCCESS); |
638 | SWAY_GIT_VERSION, SWAY_VERSION_DATE, SWAY_GIT_BRANCH); | 639 | break; |
639 | #else | ||
640 | fprintf(stdout, "version unknown\n"); | ||
641 | #endif | ||
642 | return 1; | ||
643 | case LO_BS_HL_COLOR: | 640 | case LO_BS_HL_COLOR: |
644 | if (state) { | 641 | if (state) { |
645 | state->args.colors.bs_highlight = parse_color(optarg); | 642 | state->args.colors.bs_highlight = parse_color(optarg); |
@@ -844,6 +841,10 @@ static int load_config(char *path, struct swaylock_state *state, | |||
844 | 841 | ||
845 | static struct swaylock_state state; | 842 | static struct swaylock_state state; |
846 | 843 | ||
844 | static void display_in(int fd, short mask, void *data) { | ||
845 | wl_display_dispatch(state.display); | ||
846 | } | ||
847 | |||
847 | int main(int argc, char **argv) { | 848 | int main(int argc, char **argv) { |
848 | wlr_log_init(WLR_DEBUG, NULL); | 849 | wlr_log_init(WLR_DEBUG, NULL); |
849 | initialize_pw_backend(); | 850 | initialize_pw_backend(); |
@@ -903,7 +904,11 @@ int main(int argc, char **argv) { | |||
903 | wl_list_init(&state.surfaces); | 904 | wl_list_init(&state.surfaces); |
904 | state.xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); | 905 | state.xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS); |
905 | state.display = wl_display_connect(NULL); | 906 | state.display = wl_display_connect(NULL); |
906 | assert(state.display); | 907 | if (!state.display) { |
908 | sway_abort("Unable to connect to the compositor. " | ||
909 | "If your compositor is running, check or set the " | ||
910 | "WAYLAND_DISPLAY environment variable."); | ||
911 | } | ||
907 | 912 | ||
908 | struct wl_registry *registry = wl_display_get_registry(state.display); | 913 | struct wl_registry *registry = wl_display_get_registry(state.display); |
909 | wl_registry_add_listener(registry, ®istry_listener, &state); | 914 | wl_registry_add_listener(registry, ®istry_listener, &state); |
@@ -946,9 +951,14 @@ int main(int argc, char **argv) { | |||
946 | daemonize(); | 951 | daemonize(); |
947 | } | 952 | } |
948 | 953 | ||
954 | state.eventloop = loop_create(); | ||
955 | loop_add_fd(state.eventloop, wl_display_get_fd(state.display), POLL_IN, | ||
956 | display_in, NULL); | ||
957 | |||
949 | state.run_display = true; | 958 | state.run_display = true; |
950 | while (wl_display_dispatch(state.display) != -1 && state.run_display) { | 959 | while (state.run_display) { |
951 | // This space intentionally left blank | 960 | wl_display_flush(state.display); |
961 | loop_poll(state.eventloop); | ||
952 | } | 962 | } |
953 | 963 | ||
954 | free(state.args.font); | 964 | free(state.args.font); |
diff --git a/swaylock/password.c b/swaylock/password.c index 6a956bcb..fecaecbf 100644 --- a/swaylock/password.c +++ b/swaylock/password.c | |||
@@ -8,13 +8,14 @@ | |||
8 | #include <xkbcommon/xkbcommon.h> | 8 | #include <xkbcommon/xkbcommon.h> |
9 | #include "swaylock/swaylock.h" | 9 | #include "swaylock/swaylock.h" |
10 | #include "swaylock/seat.h" | 10 | #include "swaylock/seat.h" |
11 | #include "loop.h" | ||
11 | #include "unicode.h" | 12 | #include "unicode.h" |
12 | 13 | ||
13 | void clear_password_buffer(struct swaylock_password *pw) { | 14 | void clear_password_buffer(struct swaylock_password *pw) { |
14 | // Use volatile keyword so so compiler can't optimize this out. | 15 | // Use volatile keyword so so compiler can't optimize this out. |
15 | volatile char *buffer = pw->buffer; | 16 | volatile char *buffer = pw->buffer; |
16 | volatile char zero = '\0'; | 17 | volatile char zero = '\0'; |
17 | for (size_t i = 0; i < sizeof(buffer); ++i) { | 18 | for (size_t i = 0; i < sizeof(pw->buffer); ++i) { |
18 | buffer[i] = zero; | 19 | buffer[i] = zero; |
19 | } | 20 | } |
20 | pw->len = 0; | 21 | pw->len = 0; |
@@ -39,6 +40,43 @@ static void append_ch(struct swaylock_password *pw, uint32_t codepoint) { | |||
39 | pw->len += utf8_size; | 40 | pw->len += utf8_size; |
40 | } | 41 | } |
41 | 42 | ||
43 | static void clear_indicator(void *data) { | ||
44 | struct swaylock_state *state = data; | ||
45 | state->clear_indicator_timer = NULL; | ||
46 | state->auth_state = AUTH_STATE_IDLE; | ||
47 | damage_state(state); | ||
48 | } | ||
49 | |||
50 | static void schedule_indicator_clear(struct swaylock_state *state) { | ||
51 | if (state->clear_indicator_timer) { | ||
52 | loop_remove_timer(state->eventloop, state->clear_indicator_timer); | ||
53 | } | ||
54 | state->clear_indicator_timer = loop_add_timer( | ||
55 | state->eventloop, 3000, clear_indicator, state); | ||
56 | } | ||
57 | |||
58 | static void clear_password(void *data) { | ||
59 | struct swaylock_state *state = data; | ||
60 | state->clear_password_timer = NULL; | ||
61 | state->auth_state = AUTH_STATE_CLEAR; | ||
62 | clear_password_buffer(&state->password); | ||
63 | damage_state(state); | ||
64 | schedule_indicator_clear(state); | ||
65 | } | ||
66 | |||
67 | static void schedule_password_clear(struct swaylock_state *state) { | ||
68 | if (state->clear_password_timer) { | ||
69 | loop_remove_timer(state->eventloop, state->clear_password_timer); | ||
70 | } | ||
71 | state->clear_password_timer = loop_add_timer( | ||
72 | state->eventloop, 10000, clear_password, state); | ||
73 | } | ||
74 | |||
75 | static void handle_preverify_timeout(void *data) { | ||
76 | struct swaylock_state *state = data; | ||
77 | state->verify_password_timer = NULL; | ||
78 | } | ||
79 | |||
42 | void swaylock_handle_key(struct swaylock_state *state, | 80 | void swaylock_handle_key(struct swaylock_state *state, |
43 | xkb_keysym_t keysym, uint32_t codepoint) { | 81 | xkb_keysym_t keysym, uint32_t codepoint) { |
44 | switch (keysym) { | 82 | switch (keysym) { |
@@ -50,7 +88,18 @@ void swaylock_handle_key(struct swaylock_state *state, | |||
50 | 88 | ||
51 | state->auth_state = AUTH_STATE_VALIDATING; | 89 | state->auth_state = AUTH_STATE_VALIDATING; |
52 | damage_state(state); | 90 | damage_state(state); |
53 | while (wl_display_dispatch(state->display) != -1 && state->run_display) { | 91 | |
92 | // We generally want to wait until all surfaces are showing the | ||
93 | // "verifying" state before we go and verify the password, because | ||
94 | // verifying it is a blocking operation. However, if the surface is on | ||
95 | // an output with DPMS off then it won't update, so we set a timer. | ||
96 | state->verify_password_timer = loop_add_timer( | ||
97 | state->eventloop, 50, handle_preverify_timeout, state); | ||
98 | |||
99 | while (state->run_display && state->verify_password_timer) { | ||
100 | wl_display_flush(state->display); | ||
101 | loop_poll(state->eventloop); | ||
102 | |||
54 | bool ok = 1; | 103 | bool ok = 1; |
55 | struct swaylock_surface *surface; | 104 | struct swaylock_surface *surface; |
56 | wl_list_for_each(surface, &state->surfaces, link) { | 105 | wl_list_for_each(surface, &state->surfaces, link) { |
@@ -70,6 +119,7 @@ void swaylock_handle_key(struct swaylock_state *state, | |||
70 | } | 119 | } |
71 | state->auth_state = AUTH_STATE_INVALID; | 120 | state->auth_state = AUTH_STATE_INVALID; |
72 | damage_state(state); | 121 | damage_state(state); |
122 | schedule_indicator_clear(state); | ||
73 | break; | 123 | break; |
74 | case XKB_KEY_Delete: | 124 | case XKB_KEY_Delete: |
75 | case XKB_KEY_BackSpace: | 125 | case XKB_KEY_BackSpace: |
@@ -79,11 +129,14 @@ void swaylock_handle_key(struct swaylock_state *state, | |||
79 | state->auth_state = AUTH_STATE_CLEAR; | 129 | state->auth_state = AUTH_STATE_CLEAR; |
80 | } | 130 | } |
81 | damage_state(state); | 131 | damage_state(state); |
132 | schedule_indicator_clear(state); | ||
133 | schedule_password_clear(state); | ||
82 | break; | 134 | break; |
83 | case XKB_KEY_Escape: | 135 | case XKB_KEY_Escape: |
84 | clear_password_buffer(&state->password); | 136 | clear_password_buffer(&state->password); |
85 | state->auth_state = AUTH_STATE_CLEAR; | 137 | state->auth_state = AUTH_STATE_CLEAR; |
86 | damage_state(state); | 138 | damage_state(state); |
139 | schedule_indicator_clear(state); | ||
87 | break; | 140 | break; |
88 | case XKB_KEY_Caps_Lock: | 141 | case XKB_KEY_Caps_Lock: |
89 | /* The state is getting active after this | 142 | /* The state is getting active after this |
@@ -91,6 +144,8 @@ void swaylock_handle_key(struct swaylock_state *state, | |||
91 | state->xkb.caps_lock = !state->xkb.caps_lock; | 144 | state->xkb.caps_lock = !state->xkb.caps_lock; |
92 | state->auth_state = AUTH_STATE_INPUT_NOP; | 145 | state->auth_state = AUTH_STATE_INPUT_NOP; |
93 | damage_state(state); | 146 | damage_state(state); |
147 | schedule_indicator_clear(state); | ||
148 | schedule_password_clear(state); | ||
94 | break; | 149 | break; |
95 | case XKB_KEY_Shift_L: | 150 | case XKB_KEY_Shift_L: |
96 | case XKB_KEY_Shift_R: | 151 | case XKB_KEY_Shift_R: |
@@ -104,12 +159,15 @@ void swaylock_handle_key(struct swaylock_state *state, | |||
104 | case XKB_KEY_Super_R: | 159 | case XKB_KEY_Super_R: |
105 | state->auth_state = AUTH_STATE_INPUT_NOP; | 160 | state->auth_state = AUTH_STATE_INPUT_NOP; |
106 | damage_state(state); | 161 | damage_state(state); |
162 | schedule_indicator_clear(state); | ||
163 | schedule_password_clear(state); | ||
107 | break; | 164 | break; |
108 | case XKB_KEY_u: | 165 | case XKB_KEY_u: |
109 | if (state->xkb.control) { | 166 | if (state->xkb.control) { |
110 | clear_password_buffer(&state->password); | 167 | clear_password_buffer(&state->password); |
111 | state->auth_state = AUTH_STATE_CLEAR; | 168 | state->auth_state = AUTH_STATE_CLEAR; |
112 | damage_state(state); | 169 | damage_state(state); |
170 | schedule_indicator_clear(state); | ||
113 | break; | 171 | break; |
114 | } | 172 | } |
115 | // fallthrough | 173 | // fallthrough |
@@ -118,6 +176,8 @@ void swaylock_handle_key(struct swaylock_state *state, | |||
118 | append_ch(&state->password, codepoint); | 176 | append_ch(&state->password, codepoint); |
119 | state->auth_state = AUTH_STATE_INPUT; | 177 | state->auth_state = AUTH_STATE_INPUT; |
120 | damage_state(state); | 178 | damage_state(state); |
179 | schedule_indicator_clear(state); | ||
180 | schedule_password_clear(state); | ||
121 | } | 181 | } |
122 | break; | 182 | break; |
123 | } | 183 | } |
diff --git a/swaynag/swaynag.c b/swaynag/swaynag.c index 69da851e..fa6bbe05 100644 --- a/swaynag/swaynag.c +++ b/swaynag/swaynag.c | |||
@@ -342,7 +342,11 @@ static const struct wl_registry_listener registry_listener = { | |||
342 | 342 | ||
343 | void swaynag_setup(struct swaynag *swaynag) { | 343 | void swaynag_setup(struct swaynag *swaynag) { |
344 | swaynag->display = wl_display_connect(NULL); | 344 | swaynag->display = wl_display_connect(NULL); |
345 | assert(swaynag->display); | 345 | if (!swaynag->display) { |
346 | sway_abort("Unable to connect to the compositor. " | ||
347 | "If your compositor is running, check or set the " | ||
348 | "WAYLAND_DISPLAY environment variable."); | ||
349 | } | ||
346 | 350 | ||
347 | swaynag->scale = 1; | 351 | swaynag->scale = 1; |
348 | wl_list_init(&swaynag->outputs); | 352 | wl_list_init(&swaynag->outputs); |