summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.bg.md10
-rw-r--r--README.de.md8
-rw-r--r--README.el.md8
-rw-r--r--README.fr.md8
-rw-r--r--README.it.md8
-rw-r--r--README.ja.md11
-rw-r--r--README.md13
-rw-r--r--README.pt.md8
-rw-r--r--README.ru.md10
-rw-r--r--README.uk.md8
-rw-r--r--common/loop.c180
-rw-r--r--common/meson.build1
-rw-r--r--common/pango.c15
-rw-r--r--include/ipc.h3
-rw-r--r--include/loop.h54
-rw-r--r--include/sway/config.h4
-rw-r--r--include/sway/input/seat.h11
-rw-r--r--include/sway/ipc-server.h1
-rw-r--r--include/swaybar/bar.h40
-rw-r--r--include/swaybar/config.h5
-rw-r--r--include/swaybar/event_loop.h26
-rw-r--r--include/swaybar/i3bar.h2
-rw-r--r--include/swaybar/ipc.h4
-rw-r--r--include/swaybar/status_line.h5
-rw-r--r--include/swaylock/swaylock.h4
-rw-r--r--meson.build5
-rw-r--r--sway/commands/bar.c115
-rw-r--r--sway/commands/bar/hidden_state.c34
-rw-r--r--sway/commands/bar/id.c2
-rw-r--r--sway/commands/bar/mode.c34
-rw-r--r--sway/commands/bar/status_command.c2
-rw-r--r--sway/commands/border.c2
-rw-r--r--sway/commands/gaps.c50
-rw-r--r--sway/commands/move.c8
-rw-r--r--sway/commands/sticky.c5
-rw-r--r--sway/commands/swap.c19
-rw-r--r--sway/commands/workspace.c22
-rw-r--r--sway/config.c1
-rw-r--r--sway/config/bar.c16
-rw-r--r--sway/desktop/output.c12
-rw-r--r--sway/desktop/render.c165
-rw-r--r--sway/input/cursor.c6
-rw-r--r--sway/input/keyboard.c28
-rw-r--r--sway/input/seat.c51
-rw-r--r--sway/ipc-server.c18
-rw-r--r--sway/main.c1
-rw-r--r--sway/sway-bar.5.scd16
-rw-r--r--sway/sway-input.5.scd2
-rw-r--r--sway/sway-output.5.scd66
-rw-r--r--sway/sway.1.scd2
-rw-r--r--sway/sway.5.scd86
-rw-r--r--sway/tree/arrange.c4
-rw-r--r--sway/tree/container.c4
-rw-r--r--sway/tree/view.c11
-rw-r--r--sway/tree/workspace.c7
-rw-r--r--swaybar/bar.c125
-rw-r--r--swaybar/config.c4
-rw-r--r--swaybar/event_loop.c156
-rw-r--r--swaybar/ipc.c128
-rw-r--r--swaybar/main.c8
-rw-r--r--swaybar/meson.build1
-rw-r--r--swaybar/render.c32
-rw-r--r--swaybar/status_line.c18
-rw-r--r--swaybg/main.c7
-rw-r--r--swayidle/main.c4
-rw-r--r--swaylock/main.c30
-rw-r--r--swaylock/password.c64
-rw-r--r--swaynag/swaynag.c6
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 @@
[IRC канала](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway на
irc.freenode.net).
-**Внимание**: На този етап в Sway няма да бъдат добавяни нови функции, докато не приключим с интеграцията на Sway и wlroots. Все още се оправят бъгове.
-
[![](https://sr.ht/ICd5.png)](https://sr.ht/ICd5.png)
Ако желаете, може да дарите на [Patreon страницата на автора](https://patreon.com/sircmpwn), което ще помогне за цялостното здраве и развитие на проекта.
@@ -21,14 +19,6 @@ irc.freenode.net).
Версии подписани с ключ [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)
и публикувани в [GitHub](https://github.com/swaywm/sway/releases).
-## Статус
-
-- [i3 поддръжка](https://github.com/swaywm/sway/issues/2)
-- [i3-bar поддръжка](https://github.com/swaywm/sway/issues/343)
-- [i3-gaps поддръжка](https://github.com/swaywm/sway/issues/307)
-- [IPC поддръжка](https://github.com/swaywm/sway/issues/98)
-- [Сигурност](https://github.com/swaywm/sway/issues/984)
-
## Инсталация
### От пакети
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
[B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)
signiert und [auf Github](https://github.com/swaywm/sway/releases) veröffentlicht.
-## Status
-
-- [i3-Features](https://github.com/swaywm/sway/issues/2)
-- [IPC-Features](https://github.com/swaywm/sway/issues/98)
-- [i3bar-Features](https://github.com/swaywm/sway/issues/343)
-- [i3-gaps-Features](https://github.com/swaywm/sway/issues/307)
-- [Sicherheitsfeatures](https://github.com/swaywm/sway/issues/984)
-
## Installation
### 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 και θα με βρείτ�
Οι εκδόσεις υπογράφονται ως [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A) και δημοσιεύονται στο [GitHub](https://github.com/swaywm/sway/releases).
-## Κατάσταση
-
-- [Υποστήριξη δυνατοτήτων του i3](https://github.com/swaywm/sway/issues/2)
-- [Υποστήριξη δυνατοτήτων IPC](https://github.com/swaywm/sway/issues/98)
-- [Υποστήριξη δυνατοτήτων i3bar](https://github.com/swaywm/sway/issues/343)
-- [Υποστήριξη δυνατοτήτων i3-gaps](https://github.com/swaywm/sway/issues/307)
-- [Δυνατότητες Ασφαλείας](https://github.com/swaywm/sway/issues/984)
-
## Εγκατάσταση
### Από Πακέτα
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.
Les nouvelles versions sont signées avec [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)
et publiées [sur GitHub](https://github.com/swaywm/sway/releases).
-## Statut
-
-- [support des fonctionnalités d'i3](https://github.com/swaywm/sway/issues/2)
-- [support des fonctionnalités d'IPC](https://github.com/swaywm/sway/issues/98)
-- [support des fonctionnalités d'i3bar](https://github.com/swaywm/sway/issues/343)
-- [support des fonctionnalités d'i3-gaps](https://github.com/swaywm/sway/issues/307)
-- [fonctionnalités de sécurité](https://github.com/swaywm/sway/issues/984)
-
## Installation
### À 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]
Le release sono firmate con [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)
e pubblicate [su GitHub](https://github.com/swaywm/sway/releases).
-## Status
-
-- [supporto funzionalità i3](https://github.com/swaywm/sway/issues/2)
-- [supporto funzionalità IPC](https://github.com/swaywm/sway/issues/98)
-- [supporto funzionalità i3bar](https://github.com/swaywm/sway/issues/343)
-- [supporto funzionalità i3-gaps](https://github.com/swaywm/sway/issues/307)
-- [sicurezza](https://github.com/swaywm/sway/issues/984)
-
## Installazione
### 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/)コンポジタです。
[FAQ](https://github.com/swaywm/sway/wiki)も合わせてご覧ください。
[IRC チャンネル](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on irc.freenode.net)もあります。
-**注意**: 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)をご覧ください。
-
[![](https://sr.ht/ICd5.png)](https://sr.ht/ICd5.png)
Swayの開発を支援したい場合は、[SirCmpwnのPatreon](https://patreon.com/sircmpwn)や、特定の機能に対する[報奨金のページ](https://github.com/swaywm/sway/issues/986)から寄付ができます。誰でも報奨金を請求できますし、自分の欲しい機能に報奨金を懸ける事も出来ます。またSwayのメンテナンスを支援するには、Patreonがより有用です。
## 日本語サポート
+
SirCmpwnは、日本語でのサポートをIRCとGitHubで行います。タイムゾーンはUTC-4です。
## リリースの署名
Swayのリリースは[B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)で署名され、[GitHub](https://github.com/swaywm/sway/releases)で公開されています。
-## 開発状況
-
-- [i3の機能のサポート](https://github.com/swaywm/sway/issues/2)
-- [IPCの機能のサポート](https://github.com/swaywm/sway/issues/98)
-- [i3barの機能のサポート](https://github.com/swaywm/sway/issues/343)
-- [i3-gapsの機能のサポート](https://github.com/swaywm/sway/issues/307)
-- [セキュリティ機能](https://github.com/swaywm/sway/issues/984)
-
## インストール
### パッケージから
diff --git a/README.md b/README.md
index 57bc4b79..7809a440 100644
--- a/README.md
+++ b/README.md
@@ -9,11 +9,6 @@ Read the [FAQ](https://github.com/swaywm/sway/wiki). Join the
[IRC channel](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway on
irc.freenode.net).
-**Notice**: work is well underway to port sway to
-[wlroots](https://github.com/swaywm/wlroots). This is **unstable** and
-**unsupported** - we accept patches, but are not fond of bug reports. We are no
-longer accepting bugs for 0.15.
-
If you'd like to support sway development, please contribute to [SirCmpwn's
Patreon page](https://patreon.com/sircmpwn).
@@ -22,14 +17,6 @@ Patreon page](https://patreon.com/sircmpwn).
Releases are signed with [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)
and published [on GitHub](https://github.com/swaywm/sway/releases).
-## Status
-
-- [i3 feature support](https://github.com/swaywm/sway/issues/2)
-- [IPC feature support](https://github.com/swaywm/sway/issues/98)
-- [i3bar feature support](https://github.com/swaywm/sway/issues/343)
-- [i3-gaps feature support](https://github.com/swaywm/sway/issues/307)
-- [security features](https://github.com/swaywm/sway/issues/984)
-
## Installation
### 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.
[B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)
e publicadas [no GitHub](https://github.com/swaywm/sway/releases).
-## Status
-
-- [Suporte aos recursos do i3](https://github.com/swaywm/sway/issues/2)
-- [Suporte aos recursos IPC](https://github.com/swaywm/sway/issues/98)
-- [Suporte aos recursos do i3bar](https://github.com/swaywm/sway/issues/343)
-- [Suporte aos recursos do i3-gaps](https://github.com/swaywm/sway/issues/307)
-- [Recursos de segurança](https://github.com/swaywm/sway/issues/984)
-
## Instalação
### 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/) компо�
[IRC каналу](http://webchat.freenode.net/?channels=sway&uio=d4) (#sway на
irc.freenode.net).
-**Внимание**: на данный момент ведется активная интеграция wlroots, в связи с чем разработка sway приостановлена, однако патчи продолжают приниматься.
-
[![](https://sr.ht/ICd5.png)](https://sr.ht/ICd5.png)
При желании поддержать разработку Sway вы можете пожертвовать [автору
@@ -26,14 +24,6 @@ DarkReef оказывает поддержку на русском языке в
Версии подписаны ключом [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)
и опубликованы [на GitHub'е](https://github.com/swaywm/sway/releases).
-## Статус
-
-- [Поддержка i3](https://github.com/swaywm/sway/issues/2)
-- [Поддержка i3-bar](https://github.com/swaywm/sway/issues/343)
-- [Поддержка i3-gaps](https://github.com/swaywm/sway/issues/307)
-- [Поддержка IPC](https://github.com/swaywm/sway/issues/98)
-- [Безопасность](https://github.com/swaywm/sway/issues/984)
-
## Установка
### Из пакета
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-спільноті. Будьте терплячі, вам о�
Випуски підписані ключем [B22DA89A](http://pgp.mit.edu/pks/lookup?op=vindex&search=0x52CB6609B22DA89A)
та публікуються на сторінці [GitHub](https://github.com/swaywm/sway/releases).
-## Стан розробки
-
-- [Підтримка функцій i3](https://github.com/swaywm/sway/issues/2)
-- [Реалізація IPC-протоколу i3](https://github.com/swaywm/sway/issues/98)
-- [Підтримка функцій i3bar](https://github.com/swaywm/sway/issues/343)
-- [Підтримка функцій i3-gaps](https://github.com/swaywm/sway/issues/307)
-- [Функції безпеки](https://github.com/swaywm/sway/issues/984)
-
## Встановлення
### З пакунків
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 @@
+#define _POSIX_C_SOURCE 199309L
+#include <limits.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <poll.h>
+#include <time.h>
+#include <unistd.h>
+#include "list.h"
+#include "log.h"
+#include "loop.h"
+
+struct loop_fd_event {
+ void (*callback)(int fd, short mask, void *data);
+ void *data;
+};
+
+struct loop_timer {
+ void (*callback)(void *data);
+ void *data;
+ struct timespec expiry;
+};
+
+struct loop {
+ struct pollfd *fds;
+ int fd_length;
+ int fd_capacity;
+
+ list_t *fd_events; // struct loop_fd_event
+ list_t *timers; // struct loop_timer
+};
+
+struct loop *loop_create(void) {
+ struct loop *loop = calloc(1, sizeof(struct loop));
+ if (!loop) {
+ wlr_log(WLR_ERROR, "Unable to allocate memory for loop");
+ return NULL;
+ }
+ loop->fd_capacity = 10;
+ loop->fds = malloc(sizeof(struct pollfd) * loop->fd_capacity);
+ loop->fd_events = create_list();
+ loop->timers = create_list();
+ return loop;
+}
+
+void loop_destroy(struct loop *loop) {
+ list_foreach(loop->fd_events, free);
+ list_foreach(loop->timers, free);
+ list_free(loop->fd_events);
+ list_free(loop->timers);
+ free(loop->fds);
+ free(loop);
+}
+
+void loop_poll(struct loop *loop) {
+ // Calculate next timer in ms
+ int ms = INT_MAX;
+ if (loop->timers->length) {
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ for (int i = 0; i < loop->timers->length; ++i) {
+ struct loop_timer *timer = loop->timers->items[i];
+ int timer_ms = (timer->expiry.tv_sec - now.tv_sec) * 1000;
+ timer_ms += (timer->expiry.tv_nsec - now.tv_nsec) / 1000000;
+ if (timer_ms < ms) {
+ ms = timer_ms;
+ }
+ }
+ }
+ if (ms < 0) {
+ ms = 0;
+ }
+
+ poll(loop->fds, loop->fd_length, ms);
+
+ // Dispatch fds
+ for (int i = 0; i < loop->fd_length; ++i) {
+ struct pollfd pfd = loop->fds[i];
+ struct loop_fd_event *event = loop->fd_events->items[i];
+
+ // Always send these events
+ unsigned events = pfd.events | POLLHUP | POLLERR;
+
+ if (pfd.revents & events) {
+ event->callback(pfd.fd, pfd.revents, event->data);
+ }
+ }
+
+ // Dispatch timers
+ if (loop->timers->length) {
+ struct timespec now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ for (int i = 0; i < loop->timers->length; ++i) {
+ struct loop_timer *timer = loop->timers->items[i];
+ bool expired = timer->expiry.tv_sec < now.tv_sec ||
+ (timer->expiry.tv_sec == now.tv_sec &&
+ timer->expiry.tv_nsec < now.tv_nsec);
+ if (expired) {
+ timer->callback(timer->data);
+ loop_remove_timer(loop, timer);
+ --i;
+ }
+ }
+ }
+}
+
+void loop_add_fd(struct loop *loop, int fd, short mask,
+ void (*callback)(int fd, short mask, void *data), void *data) {
+ struct loop_fd_event *event = calloc(1, sizeof(struct loop_fd_event));
+ if (!event) {
+ wlr_log(WLR_ERROR, "Unable to allocate memory for event");
+ return;
+ }
+ event->callback = callback;
+ event->data = data;
+ list_add(loop->fd_events, event);
+
+ struct pollfd pfd = {fd, mask, 0};
+
+ if (loop->fd_length == loop->fd_capacity) {
+ loop->fd_capacity += 10;
+ loop->fds = realloc(loop->fds,
+ sizeof(struct pollfd) * loop->fd_capacity);
+ }
+
+ loop->fds[loop->fd_length++] = pfd;
+}
+
+struct loop_timer *loop_add_timer(struct loop *loop, int ms,
+ void (*callback)(void *data), void *data) {
+ struct loop_timer *timer = calloc(1, sizeof(struct loop_timer));
+ if (!timer) {
+ wlr_log(WLR_ERROR, "Unable to allocate memory for timer");
+ return NULL;
+ }
+ timer->callback = callback;
+ timer->data = data;
+
+ clock_gettime(CLOCK_MONOTONIC, &timer->expiry);
+ timer->expiry.tv_sec += ms / 1000;
+
+ long int nsec = (ms % 1000) * 1000000;
+ if (timer->expiry.tv_nsec + nsec >= 1000000000) {
+ timer->expiry.tv_sec++;
+ nsec -= 1000000000;
+ }
+ timer->expiry.tv_nsec += nsec;
+
+ list_add(loop->timers, timer);
+
+ return timer;
+}
+
+bool loop_remove_fd(struct loop *loop, int fd) {
+ for (int i = 0; i < loop->fd_length; ++i) {
+ if (loop->fds[i].fd == fd) {
+ free(loop->fd_events->items[i]);
+ list_del(loop->fd_events, i);
+
+ loop->fd_length--;
+ memmove(&loop->fds[i], &loop->fds[i + 1],
+ sizeof(struct pollfd) * (loop->fd_length - i));
+
+ return true;
+ }
+ }
+ return false;
+}
+
+bool loop_remove_timer(struct loop *loop, struct loop_timer *timer) {
+ for (int i = 0; i < loop->timers->length; ++i) {
+ if (loop->timers->items[i] == timer) {
+ list_del(loop->timers, i);
+ free(timer);
+ return true;
+ }
+ }
+ return false;
+}
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(
'cairo.c',
'ipc-client.c',
'log.c',
+ 'loop.c',
'list.c',
'pango.c',
'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 @@
#include "log.h"
#include "stringop.h"
+static const char overflow[] = "[buffer overflow]";
+static const int max_chars = 16384;
+
size_t escape_markup_text(const char *src, char *dest) {
size_t length = 0;
if (dest) {
@@ -84,12 +87,12 @@ PangoLayout *get_pango_layout(cairo_t *cairo, const char *font,
void get_text_size(cairo_t *cairo, const char *font, int *width, int *height,
int *baseline, double scale, bool markup, const char *fmt, ...) {
- static char buf[2048];
+ char buf[max_chars];
va_list args;
va_start(args, fmt);
- if (vsnprintf(buf, 2048, fmt, args) >= 2048) {
- strcpy(buf, "[buffer overflow]");
+ if (vsnprintf(buf, sizeof(buf), fmt, args) >= max_chars) {
+ strcpy(&buf[sizeof(buf) - sizeof(overflow)], overflow);
}
va_end(args);
@@ -104,12 +107,12 @@ void get_text_size(cairo_t *cairo, const char *font, int *width, int *height,
void pango_printf(cairo_t *cairo, const char *font,
double scale, bool markup, const char *fmt, ...) {
- static char buf[2048];
+ char buf[max_chars];
va_list args;
va_start(args, fmt);
- if (vsnprintf(buf, 2048, fmt, args) >= 2048) {
- strcpy(buf, "[buffer overflow]");
+ if (vsnprintf(buf, sizeof(buf), fmt, args) >= max_chars) {
+ strcpy(&buf[sizeof(buf) - sizeof(overflow)], overflow);
}
va_end(args);
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 {
IPC_EVENT_BINDING = ((1<<31) | 5),
IPC_EVENT_SHUTDOWN = ((1<<31) | 6),
IPC_EVENT_TICK = ((1<<31) | 7),
+
+ // sway-specific event types
+ IPC_EVENT_BAR_STATE_UPDATE = ((1<<31) | 20),
};
#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 @@
+#ifndef _SWAY_LOOP_H
+#define _SWAY_LOOP_H
+#include <stdbool.h>
+
+/**
+ * This is an event loop system designed for sway clients, not sway itself.
+ *
+ * The loop consists of file descriptors and timers. Typically the Wayland
+ * display's file descriptor will be one of the fds in the loop.
+ */
+
+struct loop;
+struct loop_timer;
+
+/**
+ * Create an event loop.
+ */
+struct loop *loop_create(void);
+
+/**
+ * Destroy the event loop (eg. on program termination).
+ */
+void loop_destroy(struct loop *loop);
+
+/**
+ * Poll the event loop. This will block until one of the fds has data.
+ */
+void loop_poll(struct loop *loop);
+
+/**
+ * Add a file descriptor to the loop.
+ */
+void loop_add_fd(struct loop *loop, int fd, short mask,
+ void (*func)(int fd, short mask, void *data), void *data);
+
+/**
+ * Add a timer to the loop.
+ *
+ * When the timer expires, the timer will be removed from the loop and freed.
+ */
+struct loop_timer *loop_add_timer(struct loop *loop, int ms,
+ void (*callback)(void *data), void *data);
+
+/**
+ * Remove a file descriptor from the loop.
+ */
+bool loop_remove_fd(struct loop *loop, int fd);
+
+/**
+ * Remove a timer from the loop.
+ */
+bool loop_remove_timer(struct loop *loop, struct loop_timer *timer);
+
+#endif
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 {
* In "show" mode, it will always be shown on top of the active workspace.
*/
char *hidden_state;
+ bool visible_by_modifier; // only relevant in "hide" mode
/**
* Id name used to identify the bar through IPC.
*
@@ -389,7 +390,6 @@ struct sway_config {
bool show_marks;
bool tiling_drag;
- bool edge_gaps;
bool smart_gaps;
int gaps_inner;
int gaps_outer;
@@ -531,6 +531,8 @@ void free_sway_binding(struct sway_binding *sb);
void seat_execute_command(struct sway_seat *seat, struct sway_binding *binding);
+void load_swaybar(struct bar_config *bar);
+
void load_swaybars(void);
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 {
bool has_focus;
struct wl_list focus_stack; // list of containers in focus order
+ struct sway_workspace *workspace;
// If the focused layer is set, views cannot receive keyboard focus
struct wlr_layer_surface_v1 *focused_layer;
@@ -112,8 +113,16 @@ void seat_set_focus_container(struct sway_seat *seat,
void seat_set_focus_workspace(struct sway_seat *seat,
struct sway_workspace *ws);
+/**
+ * Manipulate the focus stack without triggering any other behaviour.
+ *
+ * This can be used to set focus_inactive by calling the function a second time
+ * with the real focus.
+ */
+void seat_set_raw_focus(struct sway_seat *seat, struct sway_node *node);
+
void seat_set_focus_warp(struct sway_seat *seat,
- struct sway_node *node, bool warp, bool notify);
+ struct sway_node *node, bool warp);
void seat_set_focus_surface(struct sway_seat *seat,
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,
struct sway_workspace *new, const char *change);
void ipc_event_window(struct sway_container *window, const char *change);
void ipc_event_barconfig_update(struct bar_config *bar);
+void ipc_event_bar_state_update(struct bar_config *bar);
void ipc_event_mode(const char *mode, bool pango);
void ipc_event_shutdown(const char *reason);
void ipc_event_binding(struct sway_binding *binding);
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 @@
struct swaybar_config;
struct swaybar_output;
struct swaybar_workspace;
+struct loop;
struct swaybar_pointer {
struct wl_pointer *pointer;
@@ -37,7 +38,7 @@ enum hotspot_event_handling {
};
struct swaybar_hotspot {
- struct wl_list link;
+ struct wl_list link; // swaybar_output::hotspots
int x, y, width, height;
enum hotspot_event_handling (*callback)(struct swaybar_output *output,
int x, int y, enum x11_button button, void *data);
@@ -46,6 +47,15 @@ struct swaybar_hotspot {
};
struct swaybar {
+ char *id;
+ char *mode;
+ bool mode_pango_markup;
+
+ // only relevant when bar is in "hide" mode
+ bool visible_by_modifier;
+ bool visible_by_urgency;
+ bool visible;
+
struct wl_display *display;
struct wl_compositor *compositor;
struct zwlr_layer_shell_v1 *layer_shell;
@@ -57,14 +67,16 @@ struct swaybar {
struct swaybar_pointer pointer;
struct status_line *status;
+ struct loop *eventloop;
+
int ipc_event_socketfd;
int ipc_socketfd;
- struct wl_list outputs;
+ struct wl_list outputs; // swaybar_output::link
};
struct swaybar_output {
- struct wl_list link;
+ struct wl_list link; // swaybar::outputs
struct swaybar *bar;
struct wl_output *output;
struct zxdg_output_v1 *xdg_output;
@@ -72,8 +84,8 @@ struct swaybar_output {
struct zwlr_layer_surface_v1 *layer_surface;
uint32_t wl_name;
- struct wl_list workspaces;
- struct wl_list hotspots;
+ struct wl_list workspaces; // swaybar_workspace::link
+ struct wl_list hotspots; // swaybar_hotspot::link
char *name;
bool focused;
@@ -88,7 +100,7 @@ struct swaybar_output {
};
struct swaybar_workspace {
- struct wl_list link;
+ struct wl_list link; // swaybar_output::workspaces
int num;
char *name;
bool focused;
@@ -96,10 +108,24 @@ struct swaybar_workspace {
bool urgent;
};
-bool bar_setup(struct swaybar *bar, const char *socket_path, const char *bar_id);
+bool bar_setup(struct swaybar *bar, const char *socket_path);
void bar_run(struct swaybar *bar);
void bar_teardown(struct swaybar *bar);
+/*
+ * Determines whether the bar should be visible and changes it to be so.
+ * If the current visibility of the bar is the different to what it should be,
+ * then it adds or destroys the layer surface as required,
+ * as well as sending the cont or stop signal to the status command.
+ * If the current visibility of the bar is already what it should be,
+ * then this function is a no-op, unless moving_layer is true, which occurs
+ * when the bar changes from "hide" to "dock" mode or vice versa, and the bar
+ * needs to be destroyed and re-added in order to change its layer.
+ *
+ * Returns true if the bar is now visible, otherwise false.
+ */
+bool determine_bar_visibility(struct swaybar *bar, bool moving_layer);
+void free_hotspots(struct wl_list *list);
void free_workspaces(struct wl_list *list);
#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 {
};
struct config_output {
- struct wl_list link;
+ struct wl_list link; // swaybar_config::outputs
char *name;
size_t index;
};
@@ -31,7 +31,8 @@ struct swaybar_config {
char *font;
char *sep_symbol;
char *mode;
- bool mode_pango_markup;
+ char *hidden_state;
+ char *modifier;
bool strip_workspace_numbers;
bool binding_mode_indicator;
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 @@
-#ifndef _SWAYBAR_EVENT_LOOP_H
-#define _SWAYBAR_EVENT_LOOP_H
-#include <stdbool.h>
-#include <time.h>
-
-void add_event(int fd, short mask,
- void(*cb)(int fd, short mask, void *data),
- void *data);
-
-// Not guaranteed to notify cb immediately
-void add_timer(timer_t timer,
- void(*cb)(timer_t timer, void *data),
- void *data);
-
-// Returns false if nothing exists, true otherwise
-bool remove_event(int fd);
-
-// Returns false if nothing exists, true otherwise
-bool remove_timer(timer_t timer);
-
-// Blocks and returns after sending callbacks
-void event_loop_poll(void);
-
-void init_event_loop(void);
-
-#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 @@
#include "status_line.h"
struct i3bar_block {
- struct wl_list link;
+ struct wl_list link; // status_link::blocks
int ref_count;
char *full_text, *short_text, *align;
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 @@
#include <stdbool.h>
#include "swaybar/bar.h"
-bool ipc_initialize(struct swaybar *bar, const char *bar_id);
+bool ipc_initialize(struct swaybar *bar);
bool handle_ipc_readable(struct swaybar *bar);
-void ipc_get_workspaces(struct swaybar *bar);
+bool ipc_get_workspaces(struct swaybar *bar);
void ipc_send_workspace_command(struct swaybar *bar, const char *ws);
void ipc_execute_binding(struct swaybar *bar, struct swaybar_binding *bind);
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 {
};
struct status_line {
+ struct swaybar *bar;
+
pid_t pid;
int read_fd, write_fd;
FILE *read, *write;
@@ -22,6 +24,9 @@ struct status_line {
const char *text;
struct wl_list blocks; // i3bar_block::link
+ int stop_signal;
+ int cont_signal;
+
bool click_events;
bool clicked;
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 {
};
struct swaylock_state {
+ struct loop *eventloop;
+ struct loop_timer *clear_indicator_timer; // clears the indicator
+ struct loop_timer *clear_password_timer; // clears the password buffer
+ struct loop_timer *verify_password_timer;
struct wl_display *display;
struct wl_compositor *compositor;
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()
'sway/sway.5.scd',
'sway/sway-bar.5.scd',
'sway/sway-input.5.scd',
+ 'sway/sway-output.5.scd',
'swaylock/swaylock.1.scd',
'swaymsg/swaymsg.1.scd',
'swayidle/swayidle.1.scd',
@@ -113,7 +114,7 @@ if scdoc.found()
endforeach
endif
-add_project_arguments('-DSYSCONFDIR="/@0@/@1@"'.format(prefix, sysconfdir), language : 'c')
+add_project_arguments('-DSYSCONFDIR="/@0@"'.format(sysconfdir), language : 'c')
version = get_option('sway-version')
if version != ''
@@ -156,7 +157,7 @@ subdir('swaynag')
subdir('swaylock')
config = configuration_data()
-config.set('sysconfdir', join_paths(prefix, sysconfdir))
+config.set('sysconfdir', sysconfdir)
config.set('datadir', join_paths(prefix, datadir))
config.set('prefix', prefix)
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[] = {
{ "height", bar_cmd_height },
{ "hidden_state", bar_cmd_hidden_state },
{ "icon_theme", bar_cmd_icon_theme },
- { "id", bar_cmd_id },
{ "mode", bar_cmd_mode },
{ "modifier", bar_cmd_modifier },
{ "output", bar_cmd_output },
@@ -27,7 +26,6 @@ static struct cmd_handler bar_handlers[] = {
{ "separator_symbol", bar_cmd_separator_symbol },
{ "status_command", bar_cmd_status_command },
{ "strip_workspace_numbers", bar_cmd_strip_workspace_numbers },
- { "swaybar_command", bar_cmd_swaybar_command },
{ "tray_output", bar_cmd_tray_output },
{ "tray_padding", bar_cmd_tray_padding },
{ "workspace_buttons", bar_cmd_workspace_buttons },
@@ -36,54 +34,49 @@ static struct cmd_handler bar_handlers[] = {
// Must be in alphabetical order for bsearch
static struct cmd_handler bar_config_handlers[] = {
- { "hidden_state", bar_cmd_hidden_state },
- { "mode", bar_cmd_mode }
+ { "id", bar_cmd_id },
+ { "swaybar_command", bar_cmd_swaybar_command },
};
+// Determines whether the subcommand is valid in any bar handler struct
+static bool is_subcommand(char *name) {
+ return find_handler(name, bar_handlers, sizeof(bar_handlers)) ||
+ find_handler(name, bar_config_handlers, sizeof(bar_config_handlers));
+}
+
struct cmd_results *cmd_bar(int argc, char **argv) {
struct cmd_results *error = NULL;
- if ((error = checkarg(argc, "bar", EXPECTED_AT_LEAST, 1))) {
+ if ((error = checkarg(argc, "bar", EXPECTED_AT_LEAST, 2))) {
return error;
}
- if (find_handler(argv[0], bar_config_handlers,
- sizeof(bar_config_handlers))) {
- if (config->reading) {
- return config_subcommand(argv, argc, bar_config_handlers,
- sizeof(bar_config_handlers));
- }
- return cmd_results_new(CMD_FAILURE, "bar",
- "Can only be used in config file.");
- }
-
- if (argc > 1) {
- struct bar_config *bar = NULL;
- if (!find_handler(argv[0], bar_handlers, sizeof(bar_handlers))
- && find_handler(argv[1], bar_handlers, sizeof(bar_handlers))) {
- for (int i = 0; i < config->bars->length; ++i) {
- struct bar_config *item = config->bars->items[i];
- if (strcmp(item->id, argv[0]) == 0) {
- wlr_log(WLR_DEBUG, "Selecting bar: %s", argv[0]);
- bar = item;
- break;
- }
+ bool spawn = false;
+ struct bar_config *bar = NULL;
+ if (strcmp(argv[0], "id") != 0 && is_subcommand(argv[1])) {
+ for (int i = 0; i < config->bars->length; ++i) {
+ struct bar_config *item = config->bars->items[i];
+ if (strcmp(item->id, argv[0]) == 0) {
+ wlr_log(WLR_DEBUG, "Selecting bar: %s", argv[0]);
+ bar = item;
+ break;
}
+ }
+ if (!bar) {
+ spawn = !config->reading;
+ wlr_log(WLR_DEBUG, "Creating bar: %s", argv[0]);
+ bar = default_bar_config();
if (!bar) {
- wlr_log(WLR_DEBUG, "Creating bar: %s", argv[0]);
- bar = default_bar_config();
- if (!bar) {
- return cmd_results_new(CMD_FAILURE, "bar",
- "Unable to allocate bar state");
- }
-
- bar->id = strdup(argv[0]);
+ return cmd_results_new(CMD_FAILURE, "bar",
+ "Unable to allocate bar state");
}
- config->current_bar = bar;
- ++argv; --argc;
+
+ bar->id = strdup(argv[0]);
}
+ config->current_bar = bar;
+ ++argv; --argc;
}
- if (!config->current_bar) {
+ if (!config->current_bar && config->reading) {
// Create new bar with default values
struct bar_config *bar = default_bar_config();
if (!bar) {
@@ -92,18 +85,13 @@ struct cmd_results *cmd_bar(int argc, char **argv) {
}
// set bar id
- for (int i = 0; i < config->bars->length; ++i) {
- if (bar == config->bars->items[i]) {
- const int len = 5 + numlen(i); // "bar-" + i + \0
- bar->id = malloc(len * sizeof(char));
- if (bar->id) {
- snprintf(bar->id, len, "bar-%d", i);
- } else {
- return cmd_results_new(CMD_FAILURE,
- "bar", "Unable to allocate bar ID");
- }
- break;
- }
+ const int len = 5 + numlen(config->bars->length - 1); // "bar-"+i+\0
+ bar->id = malloc(len * sizeof(char));
+ if (bar->id) {
+ snprintf(bar->id, len, "bar-%d", config->bars->length - 1);
+ } else {
+ return cmd_results_new(CMD_FAILURE,
+ "bar", "Unable to allocate bar ID");
}
// Set current bar
@@ -111,5 +99,32 @@ struct cmd_results *cmd_bar(int argc, char **argv) {
wlr_log(WLR_DEBUG, "Creating bar %s", bar->id);
}
- return config_subcommand(argv, argc, bar_handlers, sizeof(bar_handlers));
+ if (find_handler(argv[0], bar_config_handlers,
+ sizeof(bar_config_handlers))) {
+ if (config->reading) {
+ return config_subcommand(argv, argc, bar_config_handlers,
+ sizeof(bar_config_handlers));
+ } else if (spawn) {
+ for (int i = config->bars->length - 1; i >= 0; i--) {
+ struct bar_config *bar = config->bars->items[i];
+ if (bar == config->current_bar) {
+ list_del(config->bars, i);
+ free_bar_config(bar);
+ break;
+ }
+ }
+ }
+ return cmd_results_new(CMD_INVALID, "bar",
+ "Can only be used in the config file.");
+ }
+
+ struct cmd_results *res =
+ config_subcommand(argv, argc, bar_handlers, sizeof(bar_handlers));
+ if (!config->reading) {
+ if (spawn) {
+ load_swaybar(config->current_bar);
+ }
+ config->current_bar = NULL;
+ }
+ return res;
}
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,
}
// free old mode
free(old_state);
- return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+ return NULL;
}
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) {
const char *state = argv[0];
if (config->reading) {
- return bar_set_hidden_state(config->current_bar, state);
- }
-
- const char *id = NULL;
- if (argc == 2) {
- id = argv[1];
- }
- struct bar_config *bar;
- for (int i = 0; i < config->bars->length; ++i) {
- bar = config->bars->items[i];
- if (id && strcmp(id, bar->id) == 0) {
- return bar_set_hidden_state(bar, state);
- }
-
- error = bar_set_hidden_state(bar, state);
- if (error) {
- return error;
+ error = bar_set_hidden_state(config->current_bar, state);
+ } else {
+ const char *id = argc == 2 ? argv[1] : NULL;
+ for (int i = 0; i < config->bars->length; ++i) {
+ struct bar_config *bar = config->bars->items[i];
+ if (id) {
+ if (strcmp(id, bar->id) == 0) {
+ error = bar_set_hidden_state(bar, state);
+ break;
+ }
+ } else if ((error = bar_set_hidden_state(bar, state))) {
+ break;
+ }
}
}
- return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+ return error ? error : cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
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) {
const char *oldname = config->current_bar->id;
if (strcmp(name, oldname) == 0) {
return cmd_results_new(CMD_SUCCESS, NULL, NULL); // NOP
+ } else if (strcmp(name, "id") == 0) {
+ return cmd_results_new(CMD_INVALID, "id", "id cannot be 'id'");
}
// check if id is used by a previously defined bar
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
// free old mode
free(old_mode);
- return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+ return NULL;
}
struct cmd_results *bar_cmd_mode(int argc, char **argv) {
@@ -51,24 +51,20 @@ struct cmd_results *bar_cmd_mode(int argc, char **argv) {
const char *mode = argv[0];
if (config->reading) {
- return bar_set_mode(config->current_bar, mode);
- }
-
- const char *id = NULL;
- if (argc == 2) {
- id = argv[1];
- }
-
- struct bar_config *bar;
- for (int i = 0; i < config->bars->length; ++i) {
- bar = config->bars->items[i];
- if (id && strcmp(id, bar->id) == 0) {
- return bar_set_mode(bar, mode);
- }
- error = bar_set_mode(bar, mode);
- if (error) {
- return error;
+ error = bar_set_mode(config->current_bar, mode);
+ } else {
+ const char *id = argc == 2 ? argv[1] : NULL;
+ for (int i = 0; i < config->bars->length; ++i) {
+ struct bar_config *bar = config->bars->items[i];
+ if (id) {
+ if (strcmp(id, bar->id) == 0) {
+ error = bar_set_mode(bar, mode);
+ break;
+ }
+ } else if ((error = bar_set_mode(bar, mode))) {
+ break;
+ }
}
}
- return cmd_results_new(CMD_SUCCESS, NULL, NULL);
+ return error ? error : cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
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) {
}
if (config->active && !config->validating) {
- load_swaybars();
+ load_swaybar(config->current_bar);
}
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) {
border_toggle(view);
} else {
return cmd_results_new(CMD_INVALID, "border",
- "Expected 'border <none|normal|pixel|toggle>' "
+ "Expected 'border <none|normal|pixel|csd|toggle>' "
"or 'border pixel <px>'");
}
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 {
int amount;
};
-// gaps edge_gaps on|off|toggle
-static struct cmd_results *gaps_edge_gaps(int argc, char **argv) {
- struct cmd_results *error;
- if ((error = checkarg(argc, "gaps", EXPECTED_AT_LEAST, 2))) {
- return error;
- }
-
- if (strcmp(argv[1], "on") == 0) {
- config->edge_gaps = true;
- } else if (strcmp(argv[1], "off") == 0) {
- config->edge_gaps = false;
- } else if (strcmp(argv[1], "toggle") == 0) {
- if (!config->active) {
- return cmd_results_new(CMD_INVALID, "gaps",
- "Cannot toggle gaps while not running.");
- }
- config->edge_gaps = !config->edge_gaps;
- } else {
- return cmd_results_new(CMD_INVALID, "gaps",
- "gaps edge_gaps on|off|toggle");
- }
- arrange_root();
- return cmd_results_new(CMD_SUCCESS, NULL, NULL);
-}
-
// gaps inner|outer <px>
static struct cmd_results *gaps_set_defaults(int argc, char **argv) {
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) {
return cmd_results_new(CMD_INVALID, "gaps",
"Expected 'gaps inner|outer <px>'");
}
- if (amount < 0) {
- amount = 0;
- }
-
if (inner) {
- config->gaps_inner = amount;
+ config->gaps_inner = (amount >= 0) ? amount : 0;
} else {
config->gaps_outer = amount;
}
+
+ // Prevent negative outer gaps from moving windows out of the workspace.
+ if (config->gaps_outer < -config->gaps_inner) {
+ config->gaps_outer = -config->gaps_inner;
+ }
+
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
@@ -95,8 +72,12 @@ static void configure_gaps(struct sway_workspace *ws, void *_data) {
*prop -= data->amount;
break;
}
- if (*prop < 0) {
- *prop = 0;
+ // Prevent invalid gaps configurations.
+ if (ws->gaps_inner < 0) {
+ ws->gaps_inner = 0;
+ }
+ if (ws->gaps_outer < -ws->gaps_inner) {
+ ws->gaps_outer = -ws->gaps_inner;
}
arrange_workspace(ws);
}
@@ -156,7 +137,6 @@ static struct cmd_results *gaps_set_runtime(int argc, char **argv) {
return cmd_results_new(CMD_SUCCESS, NULL, NULL);
}
-// gaps edge_gaps on|off|toggle
// gaps inner|outer <px> - sets defaults for workspaces
// gaps inner|outer current|all set|plus|minus <px> - runtime only
struct cmd_results *cmd_gaps(int argc, char **argv) {
@@ -165,10 +145,6 @@ struct cmd_results *cmd_gaps(int argc, char **argv) {
return error;
}
- if (strcmp(argv[0], "edge_gaps") == 0) {
- return gaps_edge_gaps(argc, argv);
- }
-
if (argc == 2) {
return gaps_set_defaults(argc, argv);
}
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) {
if (new_output_last_ws && new_output_last_ws != new_workspace) {
struct sway_node *new_output_last_focus =
seat_get_focus_inactive(seat, &new_output_last_ws->node);
- seat_set_focus_warp(seat, new_output_last_focus, false, false);
+ seat_set_raw_focus(seat, new_output_last_focus);
}
// restore focus
@@ -556,7 +556,7 @@ static struct cmd_results *cmd_move_container(int argc, char **argv) {
focus = seat_get_focus_inactive(seat, &old_ws->node);
}
}
- seat_set_focus_warp(seat, focus, true, false);
+ seat_set_focus(seat, focus);
// clean-up, destroying parents if the container was the last child
if (old_parent) {
@@ -593,7 +593,7 @@ static void workspace_move_to_output(struct sway_workspace *workspace,
char *ws_name = workspace_next_name(old_output->wlr_output->name);
struct sway_workspace *ws = workspace_create(old_output, ws_name);
free(ws_name);
- seat_set_focus_workspace(seat, ws);
+ seat_set_raw_focus(seat, &ws->node);
}
workspace_consider_destroy(new_output_old_ws);
@@ -704,7 +704,7 @@ static struct cmd_results *cmd_move_in_direction(
}
// Hack to re-focus container
- seat_set_focus_workspace(config->handler_context.seat, new_ws);
+ seat_set_raw_focus(config->handler_context.seat, &new_ws->node);
seat_set_focus_container(config->handler_context.seat, container);
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) {
return error;
}
struct sway_container *container = config->handler_context.container;
+
+ if (container == NULL) {
+ return cmd_results_new(CMD_FAILURE, "sticky", "No current container");
+ };
+
if (!container_is_floating(container)) {
return cmd_results_new(CMD_FAILURE, "sticky",
"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,
temp->width = con1->width;
temp->height = con1->height;
temp->parent = con1->parent;
+ temp->workspace = con1->workspace;
con1->x = con2->x;
con1->y = con2->y;
@@ -34,8 +35,18 @@ static void swap_places(struct sway_container *con1,
con2->height = temp->height;
int temp_index = container_sibling_index(con1);
- container_insert_child(con2->parent, con1, container_sibling_index(con2));
- container_insert_child(temp->parent, con2, temp_index);
+ if (con2->parent) {
+ container_insert_child(con2->parent, con1,
+ container_sibling_index(con2));
+ } else {
+ workspace_insert_tiling(con2->workspace, con1,
+ container_sibling_index(con2));
+ }
+ if (temp->parent) {
+ container_insert_child(temp->parent, con2, temp_index);
+ } else {
+ workspace_insert_tiling(temp->workspace, con2, temp_index);
+ }
free(temp);
}
@@ -50,13 +61,13 @@ static void swap_focus(struct sway_container *con1,
enum sway_container_layout layout2 = container_parent_layout(con2);
if (focus == con1 && (layout2 == L_TABBED || layout2 == L_STACKED)) {
if (workspace_is_visible(ws2)) {
- seat_set_focus_warp(seat, &con2->node, false, true);
+ seat_set_focus_warp(seat, &con2->node, false);
}
seat_set_focus_container(seat, ws1 != ws2 ? con2 : con1);
} else if (focus == con2 && (layout1 == L_TABBED
|| layout1 == L_STACKED)) {
if (workspace_is_visible(ws1)) {
- seat_set_focus_warp(seat, &con1->node, false, true);
+ seat_set_focus_warp(seat, &con1->node, false);
}
seat_set_focus_container(seat, ws1 != ws2 ? con1 : con2);
} 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 @@
#define _XOPEN_SOURCE 500
#include <ctype.h>
+#include <limits.h>
#include <string.h>
#include <strings.h>
#include "sway/commands.h"
@@ -20,8 +21,8 @@ static struct workspace_config *workspace_config_find_or_create(char *ws_name) {
return NULL;
}
wsc->workspace = strdup(ws_name);
- wsc->gaps_inner = -1;
- wsc->gaps_outer = -1;
+ wsc->gaps_inner = INT_MIN;
+ wsc->gaps_outer = INT_MIN;
list_add(config->workspace_configs, wsc);
return wsc;
}
@@ -94,7 +95,16 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
return cmd_results_new(CMD_FAILURE, "workspace gaps",
"Expected 'workspace <ws> gaps inner|outer <px>'");
}
- *prop = val >= 0 ? val : 0;
+ *prop = val;
+
+ // Prevent invalid gaps configurations.
+ if (wsc->gaps_inner < 0) {
+ wsc->gaps_inner = 0;
+ }
+ if (wsc->gaps_outer < -wsc->gaps_inner) {
+ wsc->gaps_outer = -wsc->gaps_inner;
+ }
+
} else {
if (config->reading || !config->active) {
return cmd_results_new(CMD_DEFER, "workspace", NULL);
@@ -132,7 +142,11 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
strcasecmp(argv[0], "current") == 0) {
ws = workspace_by_name(argv[0]);
} else if (strcasecmp(argv[0], "back_and_forth") == 0) {
- if (!(ws = workspace_by_name(argv[0])) && prev_workspace_name) {
+ if (!prev_workspace_name) {
+ return cmd_results_new(CMD_INVALID, "workspace",
+ "There is no previous workspace");
+ }
+ if (!(ws = workspace_by_name(argv[0]))) {
ws = workspace_create(NULL, prev_workspace_name);
}
} 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) {
config->show_marks = true;
config->tiling_drag = true;
- config->edge_gaps = true;
config->smart_gaps = false;
config->gaps_inner = 0;
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 @@
#include "stringop.h"
#include "list.h"
#include "log.h"
+#include "util.h"
static void terminate_swaybar(pid_t pid) {
wlr_log(WLR_DEBUG, "Terminating swaybar %d", pid);
@@ -101,6 +102,7 @@ struct bar_config *default_bar_config(void) {
bar->binding_mode_indicator = true;
bar->verbose = false;
bar->pid = 0;
+ bar->modifier = get_modifier_mask_by_name("Mod4");
if (!(bar->mode = strdup("dock"))) {
goto cleanup;
}
@@ -226,13 +228,17 @@ static void invoke_swaybar(struct bar_config *bar) {
close(filedes[1]);
}
+void load_swaybar(struct bar_config *bar) {
+ if (bar->pid != 0) {
+ terminate_swaybar(bar->pid);
+ }
+ wlr_log(WLR_DEBUG, "Invoking swaybar for bar id '%s'", bar->id);
+ invoke_swaybar(bar);
+}
+
void load_swaybars(void) {
for (int i = 0; i < config->bars->length; ++i) {
struct bar_config *bar = config->bars->items[i];
- if (bar->pid != 0) {
- terminate_swaybar(bar->pid);
- }
- wlr_log(WLR_DEBUG, "Invoking swaybar for bar id '%s'", bar->id);
- invoke_swaybar(bar);
+ load_swaybar(bar);
}
}
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,
}
}
+static int scale_length(int length, int offset, float scale) {
+ return round((offset + length) * scale) - round(offset * scale);
+}
+
static void scale_box(struct wlr_box *box, float scale) {
- box->x *= scale;
- box->y *= scale;
- box->width *= scale;
- box->height *= scale;
+ box->width = scale_length(box->width, box->x, scale);
+ box->height = scale_length(box->height, box->y, scale);
+ box->x = round(box->x * scale);
+ box->y = round(box->y * scale);
}
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 {
float alpha;
};
+/**
+ * Apply scale to a width or height.
+ *
+ * One does not simply multiply the width by the scale. We allow fractional
+ * scaling, which means the resulting scaled width might be a decimal.
+ * So we round it.
+ *
+ * But even this can produce undesirable results depending on the X or Y offset
+ * of the box. For example, with a scale of 1.5, a box with width=1 should not
+ * scale to 2px if its X coordinate is 1, because the X coordinate would have
+ * scaled to 2px.
+ */
+static int scale_length(int length, int offset, float scale) {
+ return round((offset + length) * scale) - round(offset * scale);
+}
+
static void scale_box(struct wlr_box *box, float scale) {
- box->x *= scale;
- box->y *= scale;
- box->width *= scale;
- box->height *= scale;
+ box->width = scale_length(box->width, box->x, scale);
+ box->height = scale_length(box->height, box->y, scale);
+ box->x = round(box->x * scale);
+ box->y = round(box->y * scale);
}
static void scissor_output(struct wlr_output *wlr_output,
@@ -392,14 +408,23 @@ static void render_titlebar(struct sway_output *output,
render_rect(output->wlr_output, output_damage, &box, color);
// Single pixel right edge
- box.x = (x + width - TITLEBAR_BORDER_THICKNESS) * output_scale;
+ box.x = x + width - TITLEBAR_BORDER_THICKNESS;
+ box.y = y + TITLEBAR_BORDER_THICKNESS;
+ box.width = TITLEBAR_BORDER_THICKNESS;
+ box.height =
+ container_titlebar_height() - TITLEBAR_BORDER_THICKNESS * 2;
+ scale_box(&box, output_scale);
render_rect(output->wlr_output, output_damage, &box, color);
}
size_t inner_width = width - TITLEBAR_H_PADDING * 2;
+ int bg_y = y + TITLEBAR_BORDER_THICKNESS;
+ int ob_bg_height = scale_length(
+ (TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS) * 2 +
+ config->font_height, bg_y, output_scale);
// Marks
- size_t marks_ob_width = 0; // output-buffer-local
+ int marks_ob_width = 0; // output-buffer-local
if (config->show_marks && marks_texture) {
struct wlr_box texture_box;
wlr_texture_get_size(marks_texture,
@@ -408,15 +433,14 @@ static void render_titlebar(struct sway_output *output,
// The marks texture might be shorter than the config->font_height, in
// which case we need to pad it as evenly as possible above and below.
- int ob_padding_total = config->font_height * output_scale -
- texture_box.height;
- int ob_padding_above = floor(ob_padding_total / 2);
- int ob_padding_below = ceil(ob_padding_total / 2);
+ int ob_padding_total = ob_bg_height - texture_box.height;
+ int ob_padding_above = floor(ob_padding_total / 2.0);
+ int ob_padding_below = ceil(ob_padding_total / 2.0);
// Render texture
- texture_box.x = (x - output_x + width - TITLEBAR_H_PADDING)
- * output_scale - texture_box.width;
- texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale +
+ texture_box.x = round((x - output_x + width - TITLEBAR_H_PADDING)
+ * output_scale) - texture_box.width;
+ texture_box.y = round((bg_y - output_y) * output_scale) +
ob_padding_above;
float matrix[9];
@@ -431,29 +455,18 @@ static void render_titlebar(struct sway_output *output,
&texture_box, matrix, con->alpha);
// Padding above
- if (ob_padding_above > 0) {
- memcpy(&color, colors->background, sizeof(float) * 4);
- premultiply_alpha(color, con->alpha);
- box.x = (x + width - TITLEBAR_H_PADDING) * output_scale -
- texture_box.width;
- box.y = (y + TITLEBAR_V_PADDING) * output_scale;
- box.width = texture_box.width;
- box.height = ob_padding_above;
- render_rect(output->wlr_output, output_damage, &box, color);
- }
+ memcpy(&color, colors->background, sizeof(float) * 4);
+ premultiply_alpha(color, con->alpha);
+ box.x = texture_box.x + round(output_x * output_scale);
+ box.y = round((y + TITLEBAR_BORDER_THICKNESS) * output_scale);
+ box.width = texture_box.width;
+ box.height = ob_padding_above;
+ render_rect(output->wlr_output, output_damage, &box, color);
// Padding below
- if (ob_padding_below > 0) {
- memcpy(&color, colors->background, sizeof(float) * 4);
- premultiply_alpha(color, con->alpha);
- box.x = (x + width - TITLEBAR_H_PADDING) * output_scale -
- texture_box.width;
- box.y = (y + TITLEBAR_V_PADDING) * output_scale +
- ob_padding_above + texture_box.height;
- box.width = texture_box.width;
- box.height = ob_padding_below;
- render_rect(output->wlr_output, output_damage, &box, color);
- }
+ box.y += ob_padding_above + texture_box.height;
+ box.height = ob_padding_below;
+ render_rect(output->wlr_output, output_damage, &box, color);
}
// Title text
@@ -466,89 +479,73 @@ static void render_titlebar(struct sway_output *output,
// The title texture might be shorter than the config->font_height,
// in which case we need to pad it above and below.
- int ob_padding_above = (config->font_baseline - con->title_baseline)
- * output_scale;
- int ob_padding_below = (config->font_height - con->title_height)
- * output_scale - ob_padding_above;
+ int ob_padding_above = round((config->font_baseline -
+ con->title_baseline + TITLEBAR_V_PADDING -
+ TITLEBAR_BORDER_THICKNESS) * output_scale);
+ int ob_padding_below = ob_bg_height - ob_padding_above -
+ texture_box.height;
// Render texture
- texture_box.x = (x - output_x + TITLEBAR_H_PADDING) * output_scale;
- texture_box.y = (y - output_y + TITLEBAR_V_PADDING) * output_scale +
- ob_padding_above;
+ texture_box.x =
+ round((x - output_x + TITLEBAR_H_PADDING) * output_scale);
+ texture_box.y =
+ round((bg_y - output_y) * output_scale) + ob_padding_above;
float matrix[9];
wlr_matrix_project_box(matrix, &texture_box,
WL_OUTPUT_TRANSFORM_NORMAL,
0.0, output->wlr_output->transform_matrix);
- if (inner_width * output_scale - marks_ob_width < texture_box.width) {
- texture_box.width = inner_width * output_scale - marks_ob_width;
+ int inner_x = x - output_x + TITLEBAR_H_PADDING;
+ int ob_inner_width = scale_length(inner_width, inner_x, output_scale);
+ if (ob_inner_width - marks_ob_width < texture_box.width) {
+ texture_box.width = ob_inner_width - marks_ob_width;
}
render_texture(output->wlr_output, output_damage, title_texture,
&texture_box, matrix, con->alpha);
// Padding above
- if (ob_padding_above > 0) {
- memcpy(&color, colors->background, sizeof(float) * 4);
- premultiply_alpha(color, con->alpha);
- box.x = (x + TITLEBAR_H_PADDING) * output_scale;
- box.y = (y + TITLEBAR_V_PADDING) * output_scale;
- box.width = texture_box.width;
- box.height = ob_padding_above;
- render_rect(output->wlr_output, output_damage, &box, color);
- }
+ memcpy(&color, colors->background, sizeof(float) * 4);
+ premultiply_alpha(color, con->alpha);
+ box.x = texture_box.x + round(output_x * output_scale);
+ box.y = round((y + TITLEBAR_BORDER_THICKNESS) * output_scale);
+ box.width = texture_box.width;
+ box.height = ob_padding_above;
+ render_rect(output->wlr_output, output_damage, &box, color);
// Padding below
- if (ob_padding_below > 0) {
- memcpy(&color, colors->background, sizeof(float) * 4);
- premultiply_alpha(color, con->alpha);
- box.x = (x + TITLEBAR_H_PADDING) * output_scale;
- box.y = (y + TITLEBAR_V_PADDING) * output_scale +
- ob_padding_above + texture_box.height;
- box.width = texture_box.width;
- box.height = ob_padding_below;
- render_rect(output->wlr_output, output_damage, &box, color);
- }
+ box.y += ob_padding_above + texture_box.height;
+ box.height = ob_padding_below;
+ render_rect(output->wlr_output, output_damage, &box, color);
}
- // Padding above title
- memcpy(&color, colors->background, sizeof(float) * 4);
- premultiply_alpha(color, con->alpha);
- box.x = x + (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
- box.y = y + TITLEBAR_BORDER_THICKNESS;
- box.width = width - (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS * 2;
- box.height = TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS;
- scale_box(&box, output_scale);
- render_rect(output->wlr_output, output_damage, &box, color);
-
- // Padding below title
- box.y = (y + TITLEBAR_V_PADDING + config->font_height) * output_scale;
- render_rect(output->wlr_output, output_damage, &box, color);
-
// Filler between title and marks
- box.width = inner_width * output_scale - title_ob_width - marks_ob_width;
+ box.width =
+ round(inner_width * output_scale) - title_ob_width - marks_ob_width;
if (box.width > 0) {
- box.x = (x + TITLEBAR_H_PADDING) * output_scale + title_ob_width;
- box.y = (y + TITLEBAR_V_PADDING) * output_scale;
- box.height = config->font_height * output_scale;
+ box.x = round((x + TITLEBAR_H_PADDING) * output_scale) + title_ob_width;
+ box.y = round(bg_y * output_scale);
+ box.height = ob_bg_height;
render_rect(output->wlr_output, output_damage, &box, color);
}
// Padding left of title
left_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
box.x = x + left_offset;
- box.y = y + TITLEBAR_V_PADDING;
+ box.y = y + TITLEBAR_BORDER_THICKNESS;
box.width = TITLEBAR_H_PADDING - left_offset;
- box.height = config->font_height;
+ box.height = (TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS) * 2 +
+ config->font_height;
scale_box(&box, output_scale);
render_rect(output->wlr_output, output_damage, &box, color);
// Padding right of marks
right_offset = (layout == L_TABBED) * TITLEBAR_BORDER_THICKNESS;
box.x = x + width - TITLEBAR_H_PADDING;
- box.y = y + TITLEBAR_V_PADDING;
+ box.y = y + TITLEBAR_BORDER_THICKNESS;
box.width = TITLEBAR_H_PADDING - right_offset;
- box.height = config->font_height;
+ box.height = (TITLEBAR_V_PADDING - TITLEBAR_BORDER_THICKNESS) * 2 +
+ config->font_height;
scale_box(&box, output_scale);
render_rect(output->wlr_output, output_damage, &box, color);
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,
struct sway_output *focused_output = node_get_output(focus);
struct sway_output *output = node_get_output(node);
if (output != focused_output) {
- seat_set_focus_warp(seat, node, false, true);
+ seat_set_focus_warp(seat, node, false);
}
} else if (node->type == N_CONTAINER && node->sway_container->view) {
// Focus node if the following are true:
@@ -607,14 +607,14 @@ void cursor_send_pointer_motion(struct sway_cursor *cursor, uint32_t time_msec,
if (!wlr_seat_keyboard_has_grab(cursor->seat->wlr_seat) &&
node != prev_node &&
view_is_visible(node->sway_container->view)) {
- seat_set_focus_warp(seat, node, false, true);
+ seat_set_focus_warp(seat, node, false);
} else {
struct sway_node *next_focus =
seat_get_focus_inactive(seat, &root->node);
if (next_focus && next_focus->type == N_CONTAINER &&
next_focus->sway_container->view &&
view_is_visible(next_focus->sway_container->view)) {
- seat_set_focus_warp(seat, next_focus, false, true);
+ seat_set_focus_warp(seat, next_focus, false);
}
}
}
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 @@
#include "sway/input/input-manager.h"
#include "sway/input/keyboard.h"
#include "sway/input/seat.h"
+#include "sway/ipc-server.h"
#include "log.h"
/**
@@ -66,10 +67,10 @@ static void update_shortcut_state(struct sway_shortcut_state *state,
bool last_key_was_a_modifier = raw_modifiers != state->last_raw_modifiers;
state->last_raw_modifiers = raw_modifiers;
- if (last_key_was_a_modifier && state->last_keycode) {
- // Last pressed key before this one was a modifier
- state_erase_key(state, state->last_keycode);
- }
+ if (last_key_was_a_modifier && state->last_keycode) {
+ // Last pressed key before this one was a modifier
+ state_erase_key(state, state->last_keycode);
+ }
if (event->state == WLR_KEY_PRESSED) {
// Add current key to set; there may be duplicates
@@ -235,7 +236,6 @@ static void handle_keyboard_key(struct wl_listener *listener, void *data) {
code_modifiers);
}
-
bool handled = false;
// Identify active release binding
@@ -337,6 +337,19 @@ static int handle_keyboard_repeat(void *data) {
return 0;
}
+static void determine_bar_visibility(uint32_t modifiers) {
+ for (int i = 0; i < config->bars->length; ++i) {
+ struct bar_config *bar = config->bars->items[i];
+ if (strcmp(bar->mode, bar->hidden_state) == 0) { // both are "hide"
+ bool should_be_visible = (~modifiers & bar->modifier) == 0;
+ if (bar->visible_by_modifier != should_be_visible) {
+ bar->visible_by_modifier = should_be_visible;
+ ipc_event_bar_state_update(bar);
+ }
+ }
+ }
+}
+
static void handle_keyboard_modifiers(struct wl_listener *listener,
void *data) {
struct sway_keyboard *keyboard =
@@ -346,6 +359,9 @@ static void handle_keyboard_modifiers(struct wl_listener *listener,
keyboard->seat_device->input_device->wlr_device;
wlr_seat_set_keyboard(wlr_seat, wlr_device);
wlr_seat_keyboard_notify_modifiers(wlr_seat, &wlr_device->keyboard->modifiers);
+
+ uint32_t modifiers = wlr_keyboard_get_modifiers(wlr_device->keyboard);
+ determine_bar_visibility(modifiers);
}
struct sway_keyboard *sway_keyboard_create(struct sway_seat *seat,
@@ -464,7 +480,7 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
keyboard->keyboard_key.notify = handle_keyboard_key;
wl_list_remove(&keyboard->keyboard_modifiers.link);
- wl_signal_add( &wlr_device->keyboard->events.modifiers,
+ wl_signal_add(&wlr_device->keyboard->events.modifiers,
&keyboard->keyboard_modifiers);
keyboard->keyboard_modifiers.notify = handle_keyboard_modifiers;
}
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) {
seat_set_focus(seat, next_focus);
} else {
// Setting focus_inactive
- seat_set_focus_warp(seat, next_focus, false, false);
- seat_set_focus_warp(seat, focus, false, false);
+ seat_set_raw_focus(seat, next_focus);
+ seat_set_raw_focus(seat, focus);
}
}
@@ -623,8 +623,25 @@ static void container_raise_floating(struct sway_container *con) {
}
}
+static void set_workspace(struct sway_seat *seat,
+ struct sway_workspace *new_ws) {
+ if (seat->workspace == new_ws) {
+ return;
+ }
+ ipc_event_workspace(seat->workspace, new_ws, "focus");
+ seat->workspace = new_ws;
+}
+
+void seat_set_raw_focus(struct sway_seat *seat, struct sway_node *node) {
+ struct sway_seat_node *seat_node = seat_node_from_node(seat, node);
+ wl_list_remove(&seat_node->link);
+ wl_list_insert(&seat->focus_stack, &seat_node->link);
+ node_set_dirty(node);
+ node_set_dirty(node_get_parent(node));
+}
+
void seat_set_focus_warp(struct sway_seat *seat, struct sway_node *node,
- bool warp, bool notify) {
+ bool warp) {
if (seat->focused_layer) {
return;
}
@@ -688,34 +705,20 @@ void seat_set_focus_warp(struct sway_seat *seat, struct sway_node *node,
if (container) {
struct sway_container *parent = container->parent;
while (parent) {
- struct sway_seat_node *seat_node =
- seat_node_from_node(seat, &parent->node);
- wl_list_remove(&seat_node->link);
- wl_list_insert(&seat->focus_stack, &seat_node->link);
- node_set_dirty(&parent->node);
+ seat_set_raw_focus(seat, &parent->node);
parent = parent->parent;
}
}
if (new_workspace) {
- struct sway_seat_node *seat_node =
- seat_node_from_node(seat, &new_workspace->node);
- wl_list_remove(&seat_node->link);
- wl_list_insert(&seat->focus_stack, &seat_node->link);
- node_set_dirty(&new_workspace->node);
+ seat_set_raw_focus(seat, &new_workspace->node);
}
if (container) {
- struct sway_seat_node *seat_node =
- seat_node_from_node(seat, &container->node);
- wl_list_remove(&seat_node->link);
- wl_list_insert(&seat->focus_stack, &seat_node->link);
- node_set_dirty(&container->node);
+ seat_set_raw_focus(seat, &container->node);
seat_send_focus(&container->node, seat);
}
// emit ipc events
- if (notify && new_workspace && last_workspace != new_workspace) {
- ipc_event_workspace(last_workspace, new_workspace, "focus");
- }
+ set_workspace(seat, new_workspace);
if (container && container->view) {
ipc_event_window(container, "focus");
}
@@ -798,17 +801,17 @@ void seat_set_focus_warp(struct sway_seat *seat, struct sway_node *node,
}
void seat_set_focus(struct sway_seat *seat, struct sway_node *node) {
- seat_set_focus_warp(seat, node, true, true);
+ seat_set_focus_warp(seat, node, true);
}
void seat_set_focus_container(struct sway_seat *seat,
struct sway_container *con) {
- seat_set_focus_warp(seat, con ? &con->node : NULL, true, true);
+ seat_set_focus_warp(seat, con ? &con->node : NULL, true);
}
void seat_set_focus_workspace(struct sway_seat *seat,
struct sway_workspace *ws) {
- seat_set_focus_warp(seat, ws ? &ws->node : NULL, true, true);
+ seat_set_focus_warp(seat, ws ? &ws->node : NULL, true);
}
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) {
json_object_put(json);
}
+void ipc_event_bar_state_update(struct bar_config *bar) {
+ if (!ipc_has_event_listeners(IPC_EVENT_BAR_STATE_UPDATE)) {
+ return;
+ }
+ wlr_log(WLR_DEBUG, "Sending bar_state_update event");
+
+ json_object *json = json_object_new_object();
+ json_object_object_add(json, "id", json_object_new_string(bar->id));
+ json_object_object_add(json, "visible_by_modifier",
+ json_object_new_boolean(bar->visible_by_modifier));
+
+ const char *json_string = json_object_to_json_string(json);
+ ipc_send_event(json_string, IPC_EVENT_BAR_STATE_UPDATE);
+ json_object_put(json);
+}
+
void ipc_event_mode(const char *mode, bool pango) {
if (!ipc_has_event_listeners(IPC_EVENT_MODE)) {
return;
@@ -651,6 +667,8 @@ void ipc_client_handle_command(struct ipc_client *client) {
client->subscribed_events |= event_mask(IPC_EVENT_WORKSPACE);
} else if (strcmp(event_type, "barconfig_update") == 0) {
client->subscribed_events |= event_mask(IPC_EVENT_BARCONFIG_UPDATE);
+ } else if (strcmp(event_type, "bar_state_update") == 0) {
+ client->subscribed_events |= event_mask(IPC_EVENT_BAR_STATE_UPDATE);
} else if (strcmp(event_type, "mode") == 0) {
client->subscribed_events |= event_mask(IPC_EVENT_MODE);
} 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) {
}
}
- // TODO: switch logging over to wlroots?
if (debug) {
wlr_log_init(WLR_DEBUG, NULL);
} 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.
is given, when mouse button _n_ has been released). To disable the default
behavior for a button, use the command _nop_.
+*mode* dock|hide|invisible
+ Specifies the visibility of the bar. In _dock_ mode, it is permanently
+ visible at one edge of the screen. In _hide_ mode, it is hidden unless the
+ modifier key is pressed, though this behaviour depends on the hidden state.
+ In _invisible_ mode, it is permanently hidden. Default is _dock_.
+
+*hidden\_state* hide|show
+ Specifies the behaviour of the bar when it is in _hide_ mode. When the
+ hidden state is _hide_, then it is normally hidden, and only unhidden by
+ pressing the modifier key or in case of urgency hints. When the hidden
+ state is _show_, then it is permanently visible, drawn on top of the
+ currently visible workspace. Default is _hide_.
+
+*modifier* <Modifier>|none
+ Specifies the modifier key that shows a hidden bar. Default is _Mod4_.
+
## TRAY
Swaybar provides a system tray where third-party applications may place icons.
diff --git a/sway/sway-input.5.scd b/sway/sway-input.5.scd
index e5673452..82273ef3 100644
--- a/sway/sway-input.5.scd
+++ b/sway/sway-input.5.scd
@@ -143,4 +143,4 @@ in their own "seat").
# SEE ALSO
-*sway*(5)
+*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 @@
+sway-output(5)
+
+# NAME
+
+sway-output - output configuration commands for sway
+
+# DESCRIPTION
+
+You may combine output commands into one, like so:
+
+ output HDMI-A-1 mode 1920x1080 pos 1920,0 bg ~/wallpaper.png stretch
+
+You can get a list of output names with *swaymsg -t get\_outputs*. You may also
+match any output by using the output name "\*".
+
+# COMMANDS
+
+*output* <name> mode|resolution|res <WIDTHxHEIGHT>[@<RATE>[Hz]]
+ Configures the specified output to use the given mode. Modes are a
+ combination of width and height (in pixels) and a refresh rate that your
+ display can be configured to use. For a list of available modes for each
+ output, use *swaymsg -t get\_outputs*.
+
+ Examples:
+
+ output HDMI-A-1 mode 1920x1080
+
+ output HDMI-A-1 mode 1920x1080@60Hz
+
+*output* <name> position|pos <X> <Y>
+ Places the specified output at the specific position in the global
+ coordinate space.
+
+*output* <name> scale <factor>
+ Scales the specified output by the specified scale _factor_. An integer is
+ recommended, but fractional values are also supported. If a fractional
+ value are specified, be warned that it is not possible to faithfully
+ represent the contents of your windows - they will be rendered at the next
+ highest integral scale factor and downscaled. You may be better served by
+ setting an integral scale factor and adjusting the font size of your
+ applications to taste.
+
+*output* <name> background|bg <file> <mode> [<fallback\_color>]
+ Sets the wallpaper for the given output to the specified file, using the
+ given scaling mode (one of "stretch", "fill", "fit", "center", "tile"). If
+ the specified file cannot be accessed or if the image does fill the entire
+ output, a fallback color may be provided to cover the rest of the output.
+ __fallback\_color__ should be specified as _#RRGGBB_. Alpha is not
+ supported.
+
+*output* <name> background|bg <color> solid\_color
+ Sets the background of the given output to the specified color. _color_
+ should be specified as _#RRGGBB_. Alpha is not supported.
+
+*output* <name> transform <transform>
+ Sets the background transform to the given value. Can be one of "90", "180",
+ "270" for rotation; or "flipped", "flipped-90", "flipped-180", "flipped-270"
+ to apply a rotation and flip, or "normal" to apply no transform.
+
+*output* <name> disable|enable
+ Enables or disables the specified output (all outputs are enabled by
+ default).
+
+# SEE ALSO
+
+*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
# SEE ALSO
-*sway*(5) *swaymsg*(1) *sway-input*(5) *sway-bar*(5)
+*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.
The following commands cannot be used directly in the configuration file.
They are expected to be used with *bindsym* or at runtime through *swaymsg*(1).
-*border* normal|pixel [<n>]
+*border* none|normal|csd|pixel [<n>]
Set border style for focused window. _normal_ includes a border of
thickness _n_ and a title bar. _pixel_ is a border without title bar _n_
- pixels thick. Default is _normal_ with border thickness 2.
+ pixels thick. Default is _normal_ with border thickness 2. _csd_ is short
+ for client-side-decorations, which allows the client to draw its own
+ decorations.
-*border* none|toggle
- Set border style for focused window to _none_ or _toggle_ between the
- available border styles: _normal_, _pixel_, _none_.
+*border* toggle
+ Cycles through the available border styles.
*exit*
Exit sway and end your Wayland session.
@@ -420,15 +421,11 @@ The default colors are:
_focus\_wrapping force_. This is only available for convenience. Please
use _focus\_wrapping_ instead when possible.
-*gaps* edge\_gaps on|off|toggle
- When _on_, gaps will be added between windows and workspace edges if the
- inner gap is nonzero. When _off_, gaps will only be added between views.
- _toggle_ cannot be used in the configuration file.
-
*gaps* inner|outer <amount>
Sets default _amount_ pixels of _inner_ or _outer_ gap, where the inner
affects spacing around each view and outer affects the spacing around each
- workspace. Outer gaps are in addition to inner gaps.
+ workspace. Outer gaps are in addition to inner gaps. To reduce or remove
+ outer gaps, outer gaps can be set to a negative value.
This affects new workspaces only, and is used when the workspace doesn't
have its own gaps settings (see: workspace <ws> gaps inner|outer <amount>).
@@ -501,61 +498,6 @@ The default colors are:
Prevents windows matching <criteria> from being focused automatically when
they're created. This has no effect on the first window in a workspace.
-*output* <name> mode|resolution|res <WIDTHxHEIGHT>[@<RATE>[Hz]]
- Configures the specified output to use the given mode. Modes are a
- combination of width and height (in pixels) and a refresh rate that your
- display can be configured to use. For a list of available modes for each
- output, use *swaymsg -t get\_outputs*.
-
- Examples:
-
- output HDMI-A-1 mode 1920x1080
-
- output HDMI-A-1 mode 1920x1080@60Hz
-
-*output* <name> position|pos <X> <Y>
- Places the specified output at the specific position in the global
- coordinate space.
-
-*output* <name> scale <factor>
- Scales the specified output by the specified scale _factor_. An integer is
- recommended, but fractional values are also supported. If a fractional
- value are specified, be warned that it is not possible to faithfully
- represent the contents of your windows - they will be rendered at the next
- highest integral scale factor and downscaled. You may be better served by
- setting an integral scale factor and adjusting the font size of your
- applications to taste.
-
-*output* <name> background|bg <file> <mode> [<fallback\_color>]
- Sets the wallpaper for the given output to the specified file, using the
- given scaling mode (one of "stretch", "fill", "fit", "center", "tile"). If
- the specified file cannot be accessed or if the image does fill the entire
- output, a fallback color may be provided to cover the rest of the output.
- __fallback\_color__ should be specified as _#RRGGBB_. Alpha is not
- supported.
-
-**output** <name> background|bg <color> solid\_color
- Sets the background of the given output to the specified color. _color_
- should be specified as _#RRGGBB_. Alpha is not supported.
-
-**output** <name> transform <transform>
- Sets the background transform to the given value. Can be one of "90", "180",
- "270" for rotation; or "flipped", "flipped-90", "flipped-180", "flipped-270"
- to apply a rotation and flip, or "normal" to apply no transform.
-
-*output* <name> disable|enable
- Enables or disables the specified output (all outputs are enabled by
- default).
-
-*NOTES FOR THE OUTPUT COMMANDS*
-
-You may combine output commands into one, like so:
-
- output HDMI-A-1 mode 1920x1080 pos 1920,0 bg ~/wallpaper.png stretch
-
-You can get a list of output names with *swaymsg -t get\_outputs*. You may also
-match any output by using the output name "\*".
-
*popup\_during\_fullscreen* smart|ignore|leave\_fullscreen
Determines what to do when a fullscreen view opens a dialog.
If _smart_ (the default), the dialog will be displayed. If _ignore_, the
@@ -618,6 +560,18 @@ match any output by using the output name "\*".
*workspace\_layout* default|stacking|tabbed
Specifies the initial layout for new workspaces.
+# BAR CONTROL
+
+*bar hidden\_state* hide|show|toggle [<bar\_id>]
+ Sets the hidden state of the bar (see *sway-bar*(5)), either individually,
+ by specifying a bar id, or if none is given, for all bar instances.
+ _toggle_ switches between _hide_ and _show_.
+
+*bar mode* dock|hide|invisible|toggle [<bar\_id>]
+ Sets the mode of the bar (see *sway-bar*(5)), either individually,
+ by specifying a bar id, or if none is given, for all bar instances.
+ _toggle_ switches between _dock_ and _hide_.
+
# CRITERIA
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) {
if (config->reloading) {
return;
}
+ if (!workspace->output) {
+ // Happens when there are no outputs connected
+ return;
+ }
struct sway_output *output = workspace->output;
struct wlr_box *area = &output->usable_area;
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,
container_add_child(cont, child);
if (set_focus) {
- seat_set_focus_container(seat, cont);
- seat_set_focus_container(seat, child);
+ seat_set_raw_focus(seat, &cont->node);
+ seat_set_raw_focus(seat, &child->node);
}
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) {
}
// Use the focused workspace
- return seat_get_focused_workspace(seat);
+ struct sway_node *node = seat_get_focus_inactive(seat, &root->node);
+ if (node && node->type == N_WORKSPACE) {
+ return node->sway_workspace;
+ } else if (node && node->type == N_CONTAINER) {
+ return node->sway_container->workspace;
+ }
+
+ // If there's no focus_inactive workspace then we must be running without
+ // any outputs connected
+ return root->saved_workspaces->items[0];
}
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,
if (name) {
struct workspace_config *wsc = workspace_find_config(name);
if (wsc) {
- if (wsc->gaps_outer != -1) {
+ if (wsc->gaps_outer != INT_MIN) {
ws->gaps_outer = wsc->gaps_outer;
}
- if (wsc->gaps_inner != -1) {
+ if (wsc->gaps_inner != INT_MIN) {
ws->gaps_inner = wsc->gaps_inner;
}
}
@@ -618,9 +618,6 @@ void workspace_add_gaps(struct sway_workspace *ws) {
if (ws->current_gaps > 0) {
return;
}
- if (!config->edge_gaps) {
- return;
- }
if (config->smart_gaps) {
struct sway_seat *seat = input_manager_get_default_seat(input_manager);
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 @@
#endif
#include "swaybar/bar.h"
#include "swaybar/config.h"
-#include "swaybar/event_loop.h"
#include "swaybar/i3bar.h"
#include "swaybar/ipc.h"
#include "swaybar/status_line.h"
@@ -26,15 +25,28 @@
#include "ipc-client.h"
#include "list.h"
#include "log.h"
+#include "loop.h"
#include "pool-buffer.h"
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
#include "xdg-output-unstable-v1-client-protocol.h"
static void bar_init(struct swaybar *bar) {
bar->config = init_config();
+ bar->visible = true;
wl_list_init(&bar->outputs);
}
+void free_hotspots(struct wl_list *list) {
+ struct swaybar_hotspot *hotspot, *tmp;
+ wl_list_for_each_safe(hotspot, tmp, list, link) {
+ wl_list_remove(&hotspot->link);
+ if (hotspot->destroy) {
+ hotspot->destroy(hotspot->data);
+ }
+ free(hotspot);
+ }
+}
+
void free_workspaces(struct wl_list *list) {
struct swaybar_workspace *ws, *tmp;
wl_list_for_each_safe(ws, tmp, list, link) {
@@ -59,14 +71,8 @@ static void swaybar_output_free(struct swaybar_output *output) {
wl_output_destroy(output->output);
destroy_buffer(&output->buffers[0]);
destroy_buffer(&output->buffers[1]);
+ free_hotspots(&output->hotspots);
free_workspaces(&output->workspaces);
- struct swaybar_hotspot *hotspot, *hotspot_tmp;
- wl_list_for_each_safe(hotspot, hotspot_tmp, &output->hotspots, link) {
- if (hotspot->destroy) {
- hotspot->destroy(hotspot->data);
- }
- free(hotspot);
- }
wl_list_remove(&output->link);
free(output->name);
free(output);
@@ -75,9 +81,7 @@ static void swaybar_output_free(struct swaybar_output *output) {
static void set_output_dirty(struct swaybar_output *output) {
if (output->frame_scheduled) {
output->dirty = true;
- return;
- }
- if (output->surface) {
+ } else if (output->surface) {
render_frame(output);
}
}
@@ -335,21 +339,68 @@ const struct wl_seat_listener seat_listener = {
};
static void add_layer_surface(struct swaybar_output *output) {
- if (output->surface != NULL) {
+ if (output->layer_surface) {
return;
}
struct swaybar *bar = output->bar;
- output->surface = wl_compositor_create_surface(bar->compositor);
- assert(output->surface);
+ struct swaybar_config *config = bar->config;
+ bool hidden = strcmp(config->mode, "hide") == 0;
output->layer_surface = zwlr_layer_shell_v1_get_layer_surface(
bar->layer_shell, output->surface, output->output,
+ hidden ? ZWLR_LAYER_SHELL_V1_LAYER_TOP :
ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM, "panel");
assert(output->layer_surface);
zwlr_layer_surface_v1_add_listener(output->layer_surface,
&layer_surface_listener, output);
- zwlr_layer_surface_v1_set_anchor(output->layer_surface,
- bar->config->position);
+
+ zwlr_layer_surface_v1_set_anchor(output->layer_surface, config->position);
+ if (hidden) {
+ zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, -1);
+ }
+}
+
+static void destroy_layer_surface(struct swaybar_output *output) {
+ if (!output->layer_surface) {
+ return;
+ }
+ zwlr_layer_surface_v1_destroy(output->layer_surface);
+ wl_surface_attach(output->surface, NULL, 0, 0); // detach buffer
+ output->layer_surface = NULL;
+ output->width = 0;
+ output->frame_scheduled = false;
+}
+
+bool determine_bar_visibility(struct swaybar *bar, bool moving_layer) {
+ struct swaybar_config *config = bar->config;
+ bool visible = !(strcmp(config->mode, "invisible") == 0 ||
+ (strcmp(config->mode, config->hidden_state) == 0 // both "hide"
+ && !bar->visible_by_modifier && !bar->visible_by_urgency));
+
+ struct swaybar_output *output;
+ if (visible == bar->visible) {
+ if (visible && moving_layer) {
+ // need to destroy layer surface to move to a different layer
+ wl_list_for_each(output, &bar->outputs, link) {
+ destroy_layer_surface(output);
+ add_layer_surface(output);
+ }
+ }
+ } else {
+ bar->visible = visible;
+ wl_list_for_each(output, &bar->outputs, link) {
+ if (visible) {
+ add_layer_surface(output);
+ } else {
+ destroy_layer_surface(output);
+ }
+ }
+ wlr_log(WLR_DEBUG, "Sending %s signal to status command",
+ visible ? "cont" : "stop");
+ kill(bar->status->pid,
+ visible ? bar->status->cont_signal : bar->status->stop_signal);
+ }
+ return visible;
}
static bool bar_uses_output(struct swaybar *bar, const char *name) {
@@ -420,8 +471,11 @@ static void xdg_output_handle_done(void *data,
wl_list_remove(&output->link);
wl_list_insert(&bar->outputs, &output->link);
- add_layer_surface(output);
- set_output_dirty(output);
+ output->surface = wl_compositor_create_surface(bar->compositor);
+ assert(output->surface);
+ if (bar->visible) {
+ add_layer_surface(output);
+ }
}
}
@@ -517,22 +571,26 @@ static void set_bar_dirty(struct swaybar *bar) {
}
}
-bool bar_setup(struct swaybar *bar,
- const char *socket_path, const char *bar_id) {
+bool bar_setup(struct swaybar *bar, const char *socket_path) {
bar_init(bar);
- init_event_loop();
+ bar->eventloop = loop_create();
bar->ipc_socketfd = ipc_open_socket(socket_path);
bar->ipc_event_socketfd = ipc_open_socket(socket_path);
- if (!ipc_initialize(bar, bar_id)) {
+ if (!ipc_initialize(bar)) {
return false;
}
if (bar->config->status_command) {
bar->status = status_line_init(bar->config->status_command);
+ bar->status->bar = bar;
}
bar->display = wl_display_connect(NULL);
- assert(bar->display);
+ if (!bar->display) {
+ sway_abort("Unable to connect to the compositor. "
+ "If your compositor is running, check or set the "
+ "WAYLAND_DISPLAY environment variable.");
+ }
struct wl_registry *registry = wl_display_get_registry(bar->display);
wl_registry_add_listener(registry, &registry_listener, bar);
@@ -565,8 +623,11 @@ bool bar_setup(struct swaybar *bar,
pointer->cursor_surface = wl_compositor_create_surface(bar->compositor);
assert(pointer->cursor_surface);
- ipc_get_workspaces(bar);
- set_bar_dirty(bar);
+ if (bar->config->workspace_buttons) {
+ if (ipc_get_workspaces(bar)) {
+ set_bar_dirty(bar);
+ }
+ }
return true;
}
@@ -590,21 +651,23 @@ static void status_in(int fd, short mask, void *data) {
if (mask & (POLLHUP | POLLERR)) {
status_error(bar->status, "[error reading from status command]");
set_bar_dirty(bar);
- remove_event(fd);
+ loop_remove_fd(bar->eventloop, fd);
} else if (status_handle_readable(bar->status)) {
set_bar_dirty(bar);
}
}
void bar_run(struct swaybar *bar) {
- add_event(wl_display_get_fd(bar->display), POLLIN, display_in, bar);
- add_event(bar->ipc_event_socketfd, POLLIN, ipc_in, bar);
+ loop_add_fd(bar->eventloop, wl_display_get_fd(bar->display), POLLIN,
+ display_in, bar);
+ loop_add_fd(bar->eventloop, bar->ipc_event_socketfd, POLLIN, ipc_in, bar);
if (bar->status) {
- add_event(bar->status->read_fd, POLLIN, status_in, bar);
+ loop_add_fd(bar->eventloop, bar->status->read_fd, POLLIN,
+ status_in, bar);
}
while (1) {
wl_display_flush(bar->display);
- event_loop_poll();
+ loop_poll(bar->eventloop);
}
}
@@ -625,4 +688,6 @@ void bar_teardown(struct swaybar *bar) {
if (bar->status) {
status_line_free(bar->status);
}
+ free(bar->id);
+ free(bar->mode);
}
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) {
config->pango_markup = false;
config->position = parse_position("bottom");
config->font = strdup("monospace 10");
- config->mode = NULL;
+ config->mode = strdup("dock");
+ config->hidden_state = strdup("hide");
config->sep_symbol = NULL;
config->strip_workspace_numbers = false;
config->binding_mode_indicator = true;
@@ -84,6 +85,7 @@ void free_config(struct swaybar_config *config) {
free(config->status_command);
free(config->font);
free(config->mode);
+ free(config->hidden_state);
free(config->sep_symbol);
for (int i = 0; i < config->bindings->length; i++) {
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 @@
-#define _XOPEN_SOURCE 700
-#include <stdlib.h>
-#include <stdbool.h>
-#include <string.h>
-#include <strings.h>
-#include <poll.h>
-#include <time.h>
-#include "swaybar/event_loop.h"
-#include "list.h"
-
-struct event_item {
- void (*cb)(int fd, short mask, void *data);
- void *data;
-};
-
-struct timer_item {
- timer_t timer;
- void (*cb)(timer_t timer, void *data);
- void *data;
-};
-
-static struct {
- // The order of each must be kept consistent
- struct { /* pollfd array */
- struct pollfd *items;
- int capacity;
- int length;
- } fds;
- list_t *items; /* event_item list */
-
- // Timer list
- list_t *timers;
-} event_loop;
-
-void add_timer(timer_t timer,
- void(*cb)(timer_t timer, void *data),
- void *data) {
-
- struct timer_item *item = malloc(sizeof(struct timer_item));
- item->timer = timer;
- item->cb = cb;
- item->data = data;
-
- list_add(event_loop.timers, item);
-}
-
-void add_event(int fd, short mask,
- void(*cb)(int fd, short mask, void *data), void *data) {
-
- struct pollfd pollfd = {
- fd,
- mask,
- 0,
- };
-
- // Resize
- if (event_loop.fds.length == event_loop.fds.capacity) {
- event_loop.fds.capacity += 10;
- event_loop.fds.items = realloc(event_loop.fds.items,
- sizeof(struct pollfd) * event_loop.fds.capacity);
- }
-
- event_loop.fds.items[event_loop.fds.length++] = pollfd;
-
- struct event_item *item = malloc(sizeof(struct event_item));
- item->cb = cb;
- item->data = data;
-
- list_add(event_loop.items, item);
-
- return;
-}
-
-bool remove_event(int fd) {
- /*
- * Instead of removing events immediately, we mark them for deletion
- * and clean them up later. This is so we can call remove_event inside
- * an event callback safely.
- */
- for (int i = 0; i < event_loop.fds.length; ++i) {
- if (event_loop.fds.items[i].fd == fd) {
- event_loop.fds.items[i].fd = -1;
- return true;
- }
- }
- return false;
-}
-
-static int timer_item_timer_cmp(const void *_timer_item, const void *_timer) {
- const struct timer_item *timer_item = _timer_item;
- const timer_t *timer = _timer;
- if (timer_item->timer == *timer) {
- return 0;
- } else {
- return -1;
- }
-}
-bool remove_timer(timer_t timer) {
- int index = list_seq_find(event_loop.timers, timer_item_timer_cmp, &timer);
- if (index != -1) {
- free(event_loop.timers->items[index]);
- list_del(event_loop.timers, index);
- return true;
- }
- return false;
-}
-
-void event_loop_poll(void) {
- poll(event_loop.fds.items, event_loop.fds.length, -1);
-
- for (int i = 0; i < event_loop.fds.length; ++i) {
- struct pollfd pfd = event_loop.fds.items[i];
- struct event_item *item = (struct event_item *)event_loop.items->items[i];
-
- // Always send these events
- unsigned events = pfd.events | POLLHUP | POLLERR;
-
- if (pfd.revents & events) {
- item->cb(pfd.fd, pfd.revents, item->data);
- }
- }
-
- // Cleanup removed events
- int end = 0;
- int length = event_loop.fds.length;
- for (int i = 0; i < length; ++i) {
- if (event_loop.fds.items[i].fd == -1) {
- free(event_loop.items->items[i]);
- list_del(event_loop.items, i);
- --event_loop.fds.length;
- } else if (end != i) {
- event_loop.fds.items[end++] = event_loop.fds.items[i];
- } else {
- end = i + 1;
- }
- }
-
- // check timers
- // not tested, but seems to work
- for (int i = 0; i < event_loop.timers->length; ++i) {
- struct timer_item *item = event_loop.timers->items[i];
- int overrun = timer_getoverrun(item->timer);
- if (overrun && overrun != -1) {
- item->cb(item->timer, item->data);
- }
- }
-}
-
-void init_event_loop(void) {
- event_loop.fds.length = 0;
- event_loop.fds.capacity = 10;
- event_loop.fds.items = malloc(
- event_loop.fds.capacity * sizeof(struct pollfd));
- event_loop.items = create_list();
- event_loop.timers = create_list();
-}
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(
json_object_put(bar_config);
return false;
}
- json_object *markup, *mode, *hidden_bar, *position, *status_command;
+ json_object *markup, *mode, *hidden_state, *position, *status_command;
json_object *font, *bar_height, *wrap_scroll, *workspace_buttons, *strip_workspace_numbers;
json_object *binding_mode_indicator, *verbose, *colors, *sep_symbol, *outputs;
json_object *bindings;
json_object_object_get_ex(bar_config, "mode", &mode);
- json_object_object_get_ex(bar_config, "hidden_bar", &hidden_bar);
+ json_object_object_get_ex(bar_config, "hidden_state", &hidden_state);
json_object_object_get_ex(bar_config, "position", &position);
json_object_object_get_ex(bar_config, "status_command", &status_command);
json_object_object_get_ex(bar_config, "font", &font);
@@ -220,6 +220,14 @@ static bool ipc_parse_config(
list_add(config->bindings, binding);
}
}
+ if (hidden_state) {
+ free(config->hidden_state);
+ config->hidden_state = strdup(json_object_get_string(hidden_state));
+ }
+ if (mode) {
+ free(config->mode);
+ config->mode = strdup(json_object_get_string(mode));
+ }
struct config_output *output, *tmp;
wl_list_for_each_safe(output, tmp, &config->outputs, link) {
@@ -254,7 +262,7 @@ static bool ipc_parse_config(
return true;
}
-void ipc_get_workspaces(struct swaybar *bar) {
+bool ipc_get_workspaces(struct swaybar *bar) {
struct swaybar_output *output;
wl_list_for_each(output, &bar->outputs, link) {
free_workspaces(&output->workspaces);
@@ -266,8 +274,10 @@ void ipc_get_workspaces(struct swaybar *bar) {
json_object *results = json_tokener_parse(res);
if (!results) {
free(res);
- return;
+ return false;
}
+
+ bar->visible_by_urgency = false;
size_t length = json_object_array_length(results);
json_object *ws_json;
json_object *num, *name, *visible, *focused, *out, *urgent;
@@ -294,12 +304,16 @@ void ipc_get_workspaces(struct swaybar *bar) {
output->focused = true;
}
ws->urgent = json_object_get_boolean(urgent);
+ if (ws->urgent) {
+ bar->visible_by_urgency = true;
+ }
wl_list_insert(&output->workspaces, &ws->link);
}
}
}
json_object_put(results);
free(res);
+ return determine_bar_visibility(bar, false);
}
static void ipc_get_outputs(struct swaybar *bar) {
@@ -345,10 +359,10 @@ void ipc_execute_binding(struct swaybar *bar, struct swaybar_binding *bind) {
IPC_COMMAND, bind->command, &len));
}
-bool ipc_initialize(struct swaybar *bar, const char *bar_id) {
- uint32_t len = strlen(bar_id);
+bool ipc_initialize(struct swaybar *bar) {
+ uint32_t len = strlen(bar->id);
char *res = ipc_single_command(bar->ipc_socketfd,
- IPC_GET_BAR_CONFIG, bar_id, &len);
+ IPC_GET_BAR_CONFIG, bar->id, &len);
if (!ipc_parse_config(bar->config, res)) {
free(res);
return false;
@@ -356,56 +370,108 @@ bool ipc_initialize(struct swaybar *bar, const char *bar_id) {
free(res);
ipc_get_outputs(bar);
- const char *subscribe = "[ \"workspace\", \"mode\" ]";
- len = strlen(subscribe);
+ struct swaybar_config *config = bar->config;
+ char subscribe[128]; // suitably large buffer
+ len = snprintf(subscribe, 128,
+ "[ \"barconfig_update\" , \"bar_state_update\" %s %s ]",
+ config->binding_mode_indicator ? ", \"mode\"" : "",
+ config->workspace_buttons ? ", \"workspace\"" : "");
free(ipc_single_command(bar->ipc_event_socketfd,
IPC_SUBSCRIBE, subscribe, &len));
return true;
}
+static bool handle_bar_state_update(struct swaybar *bar, json_object *event) {
+ json_object *json_id;
+ json_object_object_get_ex(event, "id", &json_id);
+ const char *id = json_object_get_string(json_id);
+ if (strcmp(id, bar->id) != 0) {
+ return false;
+ }
+
+ json_object *visible_by_modifier;
+ json_object_object_get_ex(event, "visible_by_modifier", &visible_by_modifier);
+ bar->visible_by_modifier = json_object_get_boolean(visible_by_modifier);
+ return determine_bar_visibility(bar, false);
+}
+
+static bool handle_barconfig_update(struct swaybar *bar,
+ json_object *json_config) {
+ json_object *json_id;
+ json_object_object_get_ex(json_config, "id", &json_id);
+ const char *id = json_object_get_string(json_id);
+ if (strcmp(id, bar->id) != 0) {
+ return false;
+ }
+
+ struct swaybar_config *config = bar->config;
+
+ json_object *json_state;
+ json_object_object_get_ex(json_config, "hidden_state", &json_state);
+ const char *new_state = json_object_get_string(json_state);
+ char *old_state = config->hidden_state;
+ if (strcmp(new_state, old_state) != 0) {
+ wlr_log(WLR_DEBUG, "Changing bar hidden state to %s", new_state);
+ free(old_state);
+ config->hidden_state = strdup(new_state);
+ return determine_bar_visibility(bar, false);
+ }
+
+ free(config->mode);
+ json_object *json_mode;
+ json_object_object_get_ex(json_config, "mode", &json_mode);
+ config->mode = strdup(json_object_get_string(json_mode));
+ wlr_log(WLR_DEBUG, "Changing bar mode to %s", config->mode);
+
+ return determine_bar_visibility(bar, true);
+}
+
bool handle_ipc_readable(struct swaybar *bar) {
struct ipc_response *resp = ipc_recv_response(bar->ipc_event_socketfd);
if (!resp) {
return false;
}
+
+ json_object *result = json_tokener_parse(resp->payload);
+ if (!result) {
+ wlr_log(WLR_ERROR, "failed to parse payload as json");
+ free_ipc_response(resp);
+ return false;
+ }
+
+ bool bar_is_dirty = true;
switch (resp->type) {
case IPC_EVENT_WORKSPACE:
- ipc_get_workspaces(bar);
+ bar_is_dirty = ipc_get_workspaces(bar);
break;
case IPC_EVENT_MODE: {
- json_object *result = json_tokener_parse(resp->payload);
- if (!result) {
- free_ipc_response(resp);
- wlr_log(WLR_ERROR, "failed to parse payload as json");
- return false;
- }
json_object *json_change, *json_pango_markup;
if (json_object_object_get_ex(result, "change", &json_change)) {
const char *change = json_object_get_string(json_change);
- free(bar->config->mode);
- if (strcmp(change, "default") == 0) {
- bar->config->mode = NULL;
- } else {
- bar->config->mode = strdup(change);
- }
+ free(bar->mode);
+ bar->mode = strcmp(change, "default") != 0 ? strdup(change) : NULL;
} else {
wlr_log(WLR_ERROR, "failed to parse response");
- json_object_put(result);
- free_ipc_response(resp);
- return false;
+ bar_is_dirty = false;
+ break;
}
if (json_object_object_get_ex(result,
"pango_markup", &json_pango_markup)) {
- bar->config->mode_pango_markup = json_object_get_boolean(
- json_pango_markup);
+ bar->mode_pango_markup = json_object_get_boolean(json_pango_markup);
}
- json_object_put(result);
break;
}
+ case IPC_EVENT_BARCONFIG_UPDATE:
+ bar_is_dirty = handle_barconfig_update(bar, result);
+ break;
+ case IPC_EVENT_BAR_STATE_UPDATE:
+ bar_is_dirty = handle_bar_state_update(bar, result);
+ break;
default:
- free_ipc_response(resp);
- return false;
+ bar_is_dirty = false;
+ break;
}
+ json_object_put(result);
free_ipc_response(resp);
- return true;
+ return bar_is_dirty;
}
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) {
int main(int argc, char **argv) {
char *socket_path = NULL;
- char *bar_id = NULL;
bool debug = false;
static struct option long_options[] = {
@@ -59,7 +58,7 @@ int main(int argc, char **argv) {
socket_path = strdup(optarg);
break;
case 'b': // Type
- bar_id = strdup(optarg);
+ swaybar.id = strdup(optarg);
break;
case 'v':
fprintf(stdout, "swaybar version " SWAY_VERSION "\n");
@@ -80,7 +79,7 @@ int main(int argc, char **argv) {
wlr_log_init(WLR_ERROR, NULL);
}
- if (!bar_id) {
+ if (!swaybar.id) {
wlr_log(WLR_ERROR, "No bar_id passed. "
"Provide --bar_id or let sway start swaybar");
return 1;
@@ -96,13 +95,12 @@ int main(int argc, char **argv) {
signal(SIGTERM, sig_handler);
- if (!bar_setup(&swaybar, socket_path, bar_id)) {
+ if (!bar_setup(&swaybar, socket_path)) {
free(socket_path);
return 1;
}
free(socket_path);
- free(bar_id);
bar_run(&swaybar);
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(
'swaybar', [
'bar.c',
'config.c',
- 'event_loop.c',
'i3bar.c',
'ipc.c',
'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,
static uint32_t render_binding_mode_indicator(cairo_t *cairo,
struct swaybar_output *output, double x) {
+ const char *mode = output->bar->mode;
+ if (!mode) {
+ return 0;
+ }
+
struct swaybar_config *config = output->bar->config;
- const char *mode = config->mode;
int text_width, text_height;
get_text_size(cairo, config->font, &text_width, &text_height, NULL,
- output->scale, config->mode_pango_markup,
+ output->scale, output->bar->mode_pango_markup,
"%s", mode);
int ws_vertical_padding = WS_VERTICAL_PADDING * output->scale;
@@ -333,8 +337,8 @@ static uint32_t render_binding_mode_indicator(cairo_t *cairo,
double text_y = height / 2.0 - text_height / 2.0;
cairo_set_source_u32(cairo, config->colors.binding_mode.text);
cairo_move_to(cairo, x + width / 2 - text_width / 2, (int)floor(text_y));
- pango_printf(cairo, config->font, output->scale, config->mode_pango_markup,
- "%s", mode);
+ pango_printf(cairo, config->font, output->scale,
+ output->bar->mode_pango_markup, "%s", mode);
return output->height;
}
@@ -465,7 +469,7 @@ static uint32_t render_to_cairo(cairo_t *cairo, struct swaybar_output *output) {
max_height = h > max_height ? h : max_height;
}
}
- if (config->binding_mode_indicator && config->mode) {
+ if (config->binding_mode_indicator) {
uint32_t h = render_binding_mode_indicator(cairo, output, x);
max_height = h > max_height ? h : max_height;
}
@@ -490,16 +494,12 @@ static const struct wl_callback_listener output_frame_listener = {
void render_frame(struct swaybar_output *output) {
assert(output->surface != NULL);
-
- struct swaybar_hotspot *hotspot, *tmp;
- wl_list_for_each_safe(hotspot, tmp, &output->hotspots, link) {
- if (hotspot->destroy) {
- hotspot->destroy(hotspot->data);
- }
- wl_list_remove(&hotspot->link);
- free(hotspot);
+ if (!output->layer_surface) {
+ return;
}
+ free_hotspots(&output->hotspots);
+
cairo_surface_t *recorder = cairo_recording_surface_create(
CAIRO_CONTENT_COLOR_ALPHA, NULL);
cairo_t *cairo = cairo_create(recorder);
@@ -519,10 +519,12 @@ void render_frame(struct swaybar_output *output) {
if (config_height >= 0 && height < (uint32_t)config_height) {
height = config_height;
}
- if (height != output->height) {
+ if (height != output->height || output->width == 0) {
// Reconfigure surface
zwlr_layer_surface_v1_set_size(output->layer_surface, 0, height);
- zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, height);
+ if (strcmp(output->bar->config->mode, "dock") == 0) {
+ zwlr_layer_surface_v1_set_exclusive_zone(output->layer_surface, height);
+ }
// TODO: this could infinite loop if the compositor assigns us a
// different height than what we asked for
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 @@
#include <stdio.h>
#include <unistd.h>
#include <wlr/util/log.h>
+#include "loop.h"
#include "swaybar/bar.h"
#include "swaybar/config.h"
#include "swaybar/i3bar.h"
-#include "swaybar/event_loop.h"
#include "swaybar/status_line.h"
#include "readline.h"
static void status_line_close_fds(struct status_line *status) {
if (status->read_fd != -1) {
- remove_event(status->read_fd);
+ loop_remove_fd(status->bar->eventloop, status->read_fd);
close(status->read_fd);
status->read_fd = -1;
}
@@ -83,6 +83,17 @@ bool status_handle_readable(struct status_line *status) {
return true;
}
}
+
+ json_object *signal;
+ if (json_object_object_get_ex(header, "stop_signal", &signal)) {
+ status->stop_signal = json_object_get_int(signal);
+ wlr_log(WLR_DEBUG, "Setting stop signal to %d", status->stop_signal);
+ }
+ if (json_object_object_get_ex(header, "cont_signal", &signal)) {
+ status->cont_signal = json_object_get_int(signal);
+ wlr_log(WLR_DEBUG, "Setting cont signal to %d", status->cont_signal);
+ }
+
json_object_put(header);
wl_list_init(&status->blocks);
@@ -121,6 +132,9 @@ bool status_handle_readable(struct status_line *status) {
struct status_line *status_line_init(char *cmd) {
struct status_line *status = calloc(1, sizeof(struct status_line));
+ status->stop_signal = SIGSTOP;
+ status->cont_signal = SIGCONT;
+
status->buffer_size = 8192;
status->buffer = malloc(status->buffer_size);
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) {
}
state.display = wl_display_connect(NULL);
- assert(state.display);
+ if (!state.display) {
+ wlr_log(WLR_ERROR, "Unable to connect to the compositor. "
+ "If your compositor is running, check or set the "
+ "WAYLAND_DISPLAY environment variable.");
+ return 1;
+ }
struct wl_registry *registry = wl_display_get_registry(state.display);
wl_registry_add_listener(registry, &registry_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[]) {
state.display = wl_display_connect(NULL);
if (state.display == NULL) {
- wlr_log(WLR_ERROR, "Failed to create display");
+ wlr_log(WLR_ERROR, "Unable to connect to the compositor. "
+ "If your compositor is running, check or set the "
+ "WAYLAND_DISPLAY environment variable.");
return -3;
}
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 @@
#include "pool-buffer.h"
#include "cairo.h"
#include "log.h"
+#include "loop.h"
#include "readline.h"
#include "stringop.h"
#include "util.h"
@@ -633,13 +634,9 @@ static int parse_options(int argc, char **argv, struct swaylock_state *state,
}
break;
case 'v':
-#if defined SWAY_GIT_VERSION && defined SWAY_GIT_BRANCH && defined SWAY_VERSION_DATE
- fprintf(stdout, "swaylock version %s (%s, branch \"%s\")\n",
- SWAY_GIT_VERSION, SWAY_VERSION_DATE, SWAY_GIT_BRANCH);
-#else
- fprintf(stdout, "version unknown\n");
-#endif
- return 1;
+ fprintf(stdout, "swaylock version " SWAY_VERSION "\n");
+ exit(EXIT_SUCCESS);
+ break;
case LO_BS_HL_COLOR:
if (state) {
state->args.colors.bs_highlight = parse_color(optarg);
@@ -844,6 +841,10 @@ static int load_config(char *path, struct swaylock_state *state,
static struct swaylock_state state;
+static void display_in(int fd, short mask, void *data) {
+ wl_display_dispatch(state.display);
+}
+
int main(int argc, char **argv) {
wlr_log_init(WLR_DEBUG, NULL);
initialize_pw_backend();
@@ -903,7 +904,11 @@ int main(int argc, char **argv) {
wl_list_init(&state.surfaces);
state.xkb.context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
state.display = wl_display_connect(NULL);
- assert(state.display);
+ if (!state.display) {
+ sway_abort("Unable to connect to the compositor. "
+ "If your compositor is running, check or set the "
+ "WAYLAND_DISPLAY environment variable.");
+ }
struct wl_registry *registry = wl_display_get_registry(state.display);
wl_registry_add_listener(registry, &registry_listener, &state);
@@ -946,9 +951,14 @@ int main(int argc, char **argv) {
daemonize();
}
+ state.eventloop = loop_create();
+ loop_add_fd(state.eventloop, wl_display_get_fd(state.display), POLL_IN,
+ display_in, NULL);
+
state.run_display = true;
- while (wl_display_dispatch(state.display) != -1 && state.run_display) {
- // This space intentionally left blank
+ while (state.run_display) {
+ wl_display_flush(state.display);
+ loop_poll(state.eventloop);
}
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 @@
#include <xkbcommon/xkbcommon.h>
#include "swaylock/swaylock.h"
#include "swaylock/seat.h"
+#include "loop.h"
#include "unicode.h"
void clear_password_buffer(struct swaylock_password *pw) {
// Use volatile keyword so so compiler can't optimize this out.
volatile char *buffer = pw->buffer;
volatile char zero = '\0';
- for (size_t i = 0; i < sizeof(buffer); ++i) {
+ for (size_t i = 0; i < sizeof(pw->buffer); ++i) {
buffer[i] = zero;
}
pw->len = 0;
@@ -39,6 +40,43 @@ static void append_ch(struct swaylock_password *pw, uint32_t codepoint) {
pw->len += utf8_size;
}
+static void clear_indicator(void *data) {
+ struct swaylock_state *state = data;
+ state->clear_indicator_timer = NULL;
+ state->auth_state = AUTH_STATE_IDLE;
+ damage_state(state);
+}
+
+static void schedule_indicator_clear(struct swaylock_state *state) {
+ if (state->clear_indicator_timer) {
+ loop_remove_timer(state->eventloop, state->clear_indicator_timer);
+ }
+ state->clear_indicator_timer = loop_add_timer(
+ state->eventloop, 3000, clear_indicator, state);
+}
+
+static void clear_password(void *data) {
+ struct swaylock_state *state = data;
+ state->clear_password_timer = NULL;
+ state->auth_state = AUTH_STATE_CLEAR;
+ clear_password_buffer(&state->password);
+ damage_state(state);
+ schedule_indicator_clear(state);
+}
+
+static void schedule_password_clear(struct swaylock_state *state) {
+ if (state->clear_password_timer) {
+ loop_remove_timer(state->eventloop, state->clear_password_timer);
+ }
+ state->clear_password_timer = loop_add_timer(
+ state->eventloop, 10000, clear_password, state);
+}
+
+static void handle_preverify_timeout(void *data) {
+ struct swaylock_state *state = data;
+ state->verify_password_timer = NULL;
+}
+
void swaylock_handle_key(struct swaylock_state *state,
xkb_keysym_t keysym, uint32_t codepoint) {
switch (keysym) {
@@ -50,7 +88,18 @@ void swaylock_handle_key(struct swaylock_state *state,
state->auth_state = AUTH_STATE_VALIDATING;
damage_state(state);
- while (wl_display_dispatch(state->display) != -1 && state->run_display) {
+
+ // We generally want to wait until all surfaces are showing the
+ // "verifying" state before we go and verify the password, because
+ // verifying it is a blocking operation. However, if the surface is on
+ // an output with DPMS off then it won't update, so we set a timer.
+ state->verify_password_timer = loop_add_timer(
+ state->eventloop, 50, handle_preverify_timeout, state);
+
+ while (state->run_display && state->verify_password_timer) {
+ wl_display_flush(state->display);
+ loop_poll(state->eventloop);
+
bool ok = 1;
struct swaylock_surface *surface;
wl_list_for_each(surface, &state->surfaces, link) {
@@ -70,6 +119,7 @@ void swaylock_handle_key(struct swaylock_state *state,
}
state->auth_state = AUTH_STATE_INVALID;
damage_state(state);
+ schedule_indicator_clear(state);
break;
case XKB_KEY_Delete:
case XKB_KEY_BackSpace:
@@ -79,11 +129,14 @@ void swaylock_handle_key(struct swaylock_state *state,
state->auth_state = AUTH_STATE_CLEAR;
}
damage_state(state);
+ schedule_indicator_clear(state);
+ schedule_password_clear(state);
break;
case XKB_KEY_Escape:
clear_password_buffer(&state->password);
state->auth_state = AUTH_STATE_CLEAR;
damage_state(state);
+ schedule_indicator_clear(state);
break;
case XKB_KEY_Caps_Lock:
/* The state is getting active after this
@@ -91,6 +144,8 @@ void swaylock_handle_key(struct swaylock_state *state,
state->xkb.caps_lock = !state->xkb.caps_lock;
state->auth_state = AUTH_STATE_INPUT_NOP;
damage_state(state);
+ schedule_indicator_clear(state);
+ schedule_password_clear(state);
break;
case XKB_KEY_Shift_L:
case XKB_KEY_Shift_R:
@@ -104,12 +159,15 @@ void swaylock_handle_key(struct swaylock_state *state,
case XKB_KEY_Super_R:
state->auth_state = AUTH_STATE_INPUT_NOP;
damage_state(state);
+ schedule_indicator_clear(state);
+ schedule_password_clear(state);
break;
case XKB_KEY_u:
if (state->xkb.control) {
clear_password_buffer(&state->password);
state->auth_state = AUTH_STATE_CLEAR;
damage_state(state);
+ schedule_indicator_clear(state);
break;
}
// fallthrough
@@ -118,6 +176,8 @@ void swaylock_handle_key(struct swaylock_state *state,
append_ch(&state->password, codepoint);
state->auth_state = AUTH_STATE_INPUT;
damage_state(state);
+ schedule_indicator_clear(state);
+ schedule_password_clear(state);
}
break;
}
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 = {
void swaynag_setup(struct swaynag *swaynag) {
swaynag->display = wl_display_connect(NULL);
- assert(swaynag->display);
+ if (!swaynag->display) {
+ sway_abort("Unable to connect to the compositor. "
+ "If your compositor is running, check or set the "
+ "WAYLAND_DISPLAY environment variable.");
+ }
swaynag->scale = 1;
wl_list_init(&swaynag->outputs);