diff --git a/.builds/alpine.yml b/.builds/alpine.yml
index 7f0bef02..456837df 100644
--- a/.builds/alpine.yml
+++ b/.builds/alpine.yml
@@ -21,7 +21,7 @@ packages:
- xwayland
sources:
- https://github.com/swaywm/sway
- - https://github.com/swaywm/wlroots
+ - https://gitlab.freedesktop.org/wlroots/wlroots.git#0.15.0
tasks:
- wlroots: |
cd wlroots
diff --git a/.builds/archlinux.yml b/.builds/archlinux.yml
index a8f1dfed..c79e3fe2 100644
--- a/.builds/archlinux.yml
+++ b/.builds/archlinux.yml
@@ -18,7 +18,7 @@ packages:
- seatd
sources:
- https://github.com/swaywm/sway
- - https://github.com/swaywm/wlroots
+ - https://gitlab.freedesktop.org/wlroots/wlroots.git#0.15.0
tasks:
- wlroots: |
cd wlroots
diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml
index 1a3c8512..5aa0e3dd 100644
--- a/.builds/freebsd.yml
+++ b/.builds/freebsd.yml
@@ -26,7 +26,7 @@ packages:
- x11/xcb-util-wm
sources:
- https://github.com/swaywm/sway
-- https://github.com/swaywm/wlroots
+- https://gitlab.freedesktop.org/wlroots/wlroots.git#0.15.0
tasks:
- setup: |
cd sway
diff --git a/.clang-format b/.clang-format
deleted file mode 100644
index 24ea869d..00000000
--- a/.clang-format
+++ /dev/null
@@ -1,18 +0,0 @@
-BasedOnStyle: LLVM
-IndentWidth: 4
-TabWidth: 4
-UseTab: Always
-BreakBeforeBraces: Attach
-AllowShortIfStatementsOnASingleLine: false
-IndentCaseLabels: false
-SortIncludes: false
-ColumnLimit: 80
-AlignAfterOpenBracket: DontAlign
-BinPackParameters: true
-BinPackArguments: true
-ContinuationIndentWidth: 8
-AllowAllParametersOfDeclarationOnNextLine: false
-AllowShortLoopsOnASingleLine: true
-ReflowComments: false
-AllowAllArgumentsOnNextLine: false
-AlignOperands: DontAlign
diff --git a/README.de.md b/README.de.md
index 6e1e8ca9..01b5e9ad 100644
--- a/README.de.md
+++ b/README.de.md
@@ -15,7 +15,7 @@ Falls du sway für deine eigene Distribution als Paket bereitstellen möchtest,
sway benötigt die folgenden Pakete:
* meson\*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols\*
* pcre
diff --git a/README.dk.md b/README.dk.md
index 94c0b9eb..f712e96b 100644
--- a/README.dk.md
+++ b/README.dk.md
@@ -70,5 +70,5 @@ support til dem (gdm er kendt for at fungere temmelig godt).
[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
[GitHub releases]: https://github.com/swaywm/sway/releases
[Opsætning til udvikling]: https://github.com/swaywm/sway/wiki/Development-Setup
-[wlroots]: https://github.com/swaywm/wlroots
+[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
[scdoc]: https://git.sr.ht/~sircmpwn/scdoc
diff --git a/README.es.md b/README.es.md
index 951a2eba..7af7d90b 100644
--- a/README.es.md
+++ b/README.es.md
@@ -25,7 +25,7 @@ escriba un email a sir@cmpwn.com
Instale las dependencias:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols \*
* pcre
diff --git a/README.fr.md b/README.fr.md
index d1f4f934..359a30f9 100644
--- a/README.fr.md
+++ b/README.fr.md
@@ -79,5 +79,5 @@ bien fonctionner).
[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
[versions GitHub]: https://github.com/swaywm/sway/releases
[Configuration de développement]: https://github.com/swaywm/sway/wiki/Development-Setup
-[wlroots]: https://github.com/swaywm/wlroots
+[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
[scdoc]: https://git.sr.ht/~sircmpwn/scdoc
diff --git a/README.gr.md b/README.gr.md
index 5bb04932..4c30e29d 100644
--- a/README.gr.md
+++ b/README.gr.md
@@ -69,5 +69,5 @@ _\*Compile-time dep_
[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
[GitHub releases]: https://github.com/swaywm/sway/releases
[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup
-[wlroots]: https://github.com/swaywm/wlroots
+[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
[scdoc]: https://git.sr.ht/~sircmpwn/scdoc
\ No newline at end of file
diff --git a/README.hu.md b/README.hu.md
index 75999071..4e006f25 100644
--- a/README.hu.md
+++ b/README.hu.md
@@ -73,5 +73,5 @@ gdm-ről ismeretes, hogy egész jól működik.)
[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
[GitHub releases]: https://github.com/swaywm/sway/releases
[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup
-[wlroots]: https://github.com/swaywm/wlroots
+[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
[scdoc]: https://git.sr.ht/~sircmpwn/scdoc
diff --git a/README.ir.md b/README.ir.md
index 890a0fd2..4542b93b 100644
--- a/README.ir.md
+++ b/README.ir.md
@@ -1,9 +1,7 @@
-
-
# sway
-sway یک کامپوزیتور الهام گرفته از [i3](https://i3wm.org/) بر روی [Wayland](http://wayland.freedesktop.org/) است. [سوالهای متداول](https://github.com/swaywm/sway/wiki) را بخوانید. در [کانال
-IRC](http://web.libera.chat/gamja/?channels=sway&uio=d4) عضو شوید (#sway sur
+sway یک کامپوزیتور الهام گرفته از [i3](https://i3wm.org/) بر روی [Wayland](http://wayland.freedesktop.org/) است. [سوالهای متداول](https://github.com/swaywm/sway/wiki) را بخوانید. در [کانال
+IRC](http://web.libera.chat/gamja/?channels=sway&uio=d4) عضو شوید (#sway در
irc.libera.chat).
برای حمایت از تیم توسعه sway به [صفحه
@@ -17,7 +15,7 @@ Patreon با نام کاربری SirCmpwn](https://patreon.com/sircmpwn) مرا
### از بستههای رسمی
-sway در بستههای رسمی توزیعهای مختلف وجود دارد. بسته «sway» را نصب کنید. در صورتی که بسته رسمی وجود نداشت، برای آگاهی بیشتر درباره نصب روی توزیعتان به این [صفحه راهنما](https://github.com/swaywm/sway/wiki/Unsupported-packages) مراجعه کنید.
+sway در بستههای رسمی توزیعهای مختلف وجود دارد. بسته «sway» را نصب کنید. در صورتی که بسته رسمی وجود نداشت، برای آگاهی بیشتر درباره نصب روی توزیعتان به این [صفحه راهنما](https://github.com/swaywm/sway/wiki/Unsupported-packages) مراجعه کنید.
اگر به ایجاد بسته sway برای توزیعتان علاقهمند هستید، از کانال IRC استفاده کنید یا به sir@cmpwn.com ایمیل بزنید.
@@ -28,7 +26,7 @@ sway در بستههای رسمی توزیعهای مختلف وجود د
بستههای مورد نیاز:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols \*
* pcre
@@ -42,21 +40,16 @@ sway در بستههای رسمی توزیعهای مختلف وجود د
_\*نیازمندیهای زمان کامپایل برنامه_
این فرمانها را اجرا کنید:
-
meson build
ninja -C build
sudo ninja -C build install
-
-
روی سیستمهای بدون logind، باید فرمان زیر را برای suid کردن باینری sway اجرا کنید:
-
sudo chmod a+s /usr/local/bin/sway
-
-sway پس از startup مجوزهای دسترسی root را رها میکند.
+sway پس از startup مجوزهای دسترسی root را رها میکند.
### شخصی سازی و تنظیمات
@@ -64,7 +57,4 @@ sway پس از startup مجوزهای دسترسی root را رها میکن
## اجرا
-در محیط TTY کافیست `sway` را اجرا کنید. ممکن است ابزارهای مدیریت نمایشگری نیز برای این کار وجود داشته باشند اما از طرف sway پشتیبانی نمیشوند (gdm عملکرد خوبی در این زمینه دارد).
-
-
-
+در محیط TTY کافیست `sway` را اجرا کنید. ممکن است ابزارهای مدیریت نمایشگری نیز برای این کار وجود داشته باشند اما از طرف sway پشتیبانی نمیشوند (gdm عملکرد خوبی در این زمینه دارد).
diff --git a/README.ja.md b/README.ja.md
index 7af54fb2..786e169c 100644
--- a/README.ja.md
+++ b/README.ja.md
@@ -27,7 +27,7 @@ Swayは沢山のディストリビューションで提供されています。"
次の依存パッケージをインストールしてください:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols \*
* pcre
diff --git a/README.ko.md b/README.ko.md
index 76ce2f4d..1086da0c 100644
--- a/README.ko.md
+++ b/README.ko.md
@@ -24,7 +24,7 @@ IRC 채널을 방문하거나 sir@cmpwn.com으로 이메일을 보내 상담 받
다음 의존 패키지들을 설치해 주세요:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols \*
* pcre
diff --git a/README.md b/README.md
index 3367f846..8c252e9e 100644
--- a/README.md
+++ b/README.md
@@ -87,5 +87,5 @@ sway (gdm is known to work fairly well).
[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
[GitHub releases]: https://github.com/swaywm/sway/releases
[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup
-[wlroots]: https://github.com/swaywm/wlroots
+[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
[scdoc]: https://git.sr.ht/~sircmpwn/scdoc
diff --git a/README.nl.md b/README.nl.md
index 3351db39..c0a93063 100644
--- a/README.nl.md
+++ b/README.nl.md
@@ -25,7 +25,7 @@ kanaal of stuur een e-mail naar sir@cmpwn.com voor advies.
Afhankelijkheden installeren:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols \*
* pcre
diff --git a/README.pl.md b/README.pl.md
index da987b7c..6d376b68 100644
--- a/README.pl.md
+++ b/README.pl.md
@@ -25,7 +25,7 @@ adres sir@cmpwn.com w celu uzyskania wskazówek.
Zainstaluj zależności:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols \*
* pcre
diff --git a/README.pt.md b/README.pt.md
index 7d449ef3..92a4b54d 100644
--- a/README.pt.md
+++ b/README.pt.md
@@ -27,7 +27,7 @@ Verifique [essa página da wiki](https://github.com/swaywm/sway/wiki/Development
Instale as dependências:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols \*
* pcre
diff --git a/README.ro.md b/README.ro.md
index 79524b79..f7785b8f 100644
--- a/README.ro.md
+++ b/README.ro.md
@@ -22,7 +22,7 @@ Dacă sunteți interesați in a crea pachete pentru distribuția voastră, infor
Dependențe pentru instalare:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols \*
* pcre
diff --git a/README.ru.md b/README.ru.md
index 70396905..d563859c 100644
--- a/README.ru.md
+++ b/README.ru.md
@@ -70,5 +70,5 @@ sway (gdm работает довольно неплохо).
[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
[GitHub releases]: https://github.com/swaywm/sway/releases
[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup
-[wlroots]: https://github.com/swaywm/wlroots
+[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
[scdoc]: https://git.sr.ht/~sircmpwn/scdoc
diff --git a/README.tr.md b/README.tr.md
index c0f72d72..5c98a538 100644
--- a/README.tr.md
+++ b/README.tr.md
@@ -64,5 +64,5 @@ TTY'den `sway` çalıştırın. Bazı görüntü yöneticileriyle(display manag
[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
[GitHub releases]: https://github.com/swaywm/sway/releases
[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup
-[wlroots]: https://github.com/swaywm/wlroots
+[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
[scdoc]: https://git.sr.ht/~sircmpwn/scdoc
diff --git a/README.uk.md b/README.uk.md
index 3d7402de..ff9ebec3 100644
--- a/README.uk.md
+++ b/README.uk.md
@@ -36,7 +36,7 @@ Sway доступний у багатьох дистрибутивах Linux (а
Встановіть залежності:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols \*
* pcre
diff --git a/README.zh-CN.md b/README.zh-CN.md
index ecb46789..561d6c14 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -25,7 +25,7 @@ Sway 在很多发行版中可用. 尝试在你的发行版中安装 "sway" 包.
安装依赖:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols \*
* pcre
diff --git a/README.zh-TW.md b/README.zh-TW.md
index 4fd656da..bc30b903 100644
--- a/README.zh-TW.md
+++ b/README.zh-TW.md
@@ -25,7 +25,7 @@ Sway 在許多發行版都有提供。請自己嘗試於你的發行版安裝
相依套件:
* meson \*
-* [wlroots](https://github.com/swaywm/wlroots)
+* [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland
* wayland-protocols \*
* pcre
diff --git a/common/util.c b/common/util.c
index 199f3ee1..5d4c0673 100644
--- a/common/util.c
+++ b/common/util.c
@@ -80,6 +80,12 @@ enum movement_unit parse_movement_unit(const char *unit) {
int parse_movement_amount(int argc, char **argv,
struct movement_amount *amount) {
+ if (!sway_assert(argc > 0, "Expected args in parse_movement_amount")) {
+ amount->amount = 0;
+ amount->unit = MOVEMENT_UNIT_INVALID;
+ return 0;
+ }
+
char *err;
amount->amount = (int)strtol(argv[0], &err, 10);
if (*err) {
diff --git a/include/ipc-client.h b/include/ipc-client.h
index d3895023..9c5712d7 100644
--- a/include/ipc-client.h
+++ b/include/ipc-client.h
@@ -1,6 +1,9 @@
#ifndef _SWAY_IPC_CLIENT_H
#define _SWAY_IPC_CLIENT_H
+// arbitrary number, it's probably sufficient, higher number = more memory usage
+#define JSON_MAX_DEPTH 512
+
#include
#include
#include
diff --git a/include/sway/commands.h b/include/sway/commands.h
index 4be40870..2746ef28 100644
--- a/include/sway/commands.h
+++ b/include/sway/commands.h
@@ -112,6 +112,7 @@ sway_cmd cmd_border;
sway_cmd cmd_client_noop;
sway_cmd cmd_client_focused;
sway_cmd cmd_client_focused_inactive;
+sway_cmd cmd_client_focused_tab_title;
sway_cmd cmd_client_unfocused;
sway_cmd cmd_client_urgent;
sway_cmd cmd_client_placeholder;
@@ -284,6 +285,7 @@ sway_cmd output_cmd_max_render_time;
sway_cmd output_cmd_mode;
sway_cmd output_cmd_modeline;
sway_cmd output_cmd_position;
+sway_cmd output_cmd_render_bit_depth;
sway_cmd output_cmd_scale;
sway_cmd output_cmd_scale_filter;
sway_cmd output_cmd_subpixel;
diff --git a/include/sway/config.h b/include/sway/config.h
index 46dd4ffe..fda0e83f 100644
--- a/include/sway/config.h
+++ b/include/sway/config.h
@@ -247,6 +247,12 @@ enum scale_filter_mode {
SCALE_FILTER_SMART,
};
+enum render_bit_depth {
+ RENDER_BIT_DEPTH_DEFAULT, // the default is currently 8
+ RENDER_BIT_DEPTH_8,
+ RENDER_BIT_DEPTH_10,
+};
+
/**
* Size and position configuration for a particular output.
*
@@ -266,6 +272,7 @@ struct output_config {
enum wl_output_subpixel subpixel;
int max_render_time; // In milliseconds
int adaptive_sync;
+ enum render_bit_depth render_bit_depth;
char *background;
char *background_option;
@@ -283,6 +290,12 @@ struct side_gaps {
int left;
};
+enum smart_gaps_mode {
+ SMART_GAPS_OFF,
+ SMART_GAPS_ON,
+ SMART_GAPS_INVERSE_OUTER,
+};
+
/**
* Stores configuration for a workspace, regardless of whether the workspace
* exists.
@@ -512,7 +525,7 @@ struct sway_config {
bool tiling_drag;
int tiling_drag_threshold;
- bool smart_gaps;
+ enum smart_gaps_mode smart_gaps;
int gaps_inner;
struct side_gaps gaps_outer;
@@ -535,12 +548,15 @@ struct sway_config {
struct {
struct border_colors focused;
struct border_colors focused_inactive;
+ struct border_colors focused_tab_title;
struct border_colors unfocused;
struct border_colors urgent;
struct border_colors placeholder;
float background[4];
} border_colors;
+ bool has_focused_tab_title;
+
// floating view
int32_t floating_maximum_width;
int32_t floating_maximum_height;
diff --git a/include/sway/layers.h b/include/sway/layers.h
index 224dc5e6..14816861 100644
--- a/include/sway/layers.h
+++ b/include/sway/layers.h
@@ -25,6 +25,8 @@ struct sway_layer_surface {
bool mapped;
struct wlr_box extent;
enum zwlr_layer_shell_v1_layer layer;
+
+ struct wl_list subsurfaces;
};
struct sway_layer_popup {
@@ -44,6 +46,7 @@ struct sway_layer_popup {
struct sway_layer_subsurface {
struct wlr_subsurface *wlr_subsurface;
struct sway_layer_surface *layer_surface;
+ struct wl_list link;
struct wl_listener map;
struct wl_listener unmap;
diff --git a/include/sway/output.h b/include/sway/output.h
index 5dfe0fff..26b9709f 100644
--- a/include/sway/output.h
+++ b/include/sway/output.h
@@ -48,7 +48,7 @@ struct sway_output {
struct wl_listener damage_frame;
struct {
- struct wl_signal destroy;
+ struct wl_signal disable;
} events;
struct timespec last_presentation;
diff --git a/include/sway/server.h b/include/sway/server.h
index 88dda097..0bd860b2 100644
--- a/include/sway/server.h
+++ b/include/sway/server.h
@@ -4,6 +4,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -32,13 +33,16 @@ struct sway_server {
const char *socket;
struct wlr_backend *backend;
- struct wlr_backend *noop_backend;
// secondary headless backend used for creating virtual outputs on-the-fly
struct wlr_backend *headless_backend;
+ struct wlr_renderer *renderer;
+ struct wlr_allocator *allocator;
struct wlr_compositor *compositor;
struct wl_listener compositor_new_surface;
+ struct wlr_linux_dmabuf_v1 *linux_dmabuf_v1;
+
struct wlr_data_device_manager *data_device_manager;
struct sway_input_manager *input;
@@ -137,6 +141,8 @@ void server_fini(struct sway_server *server);
bool server_start(struct sway_server *server);
void server_run(struct sway_server *server);
+void restore_nofile_limit(void);
+
void handle_compositor_new_surface(struct wl_listener *listener, void *data);
void handle_new_output(struct wl_listener *listener, void *data);
diff --git a/include/sway/tree/container.h b/include/sway/tree/container.h
index 97fa98c1..05761150 100644
--- a/include/sway/tree/container.h
+++ b/include/sway/tree/container.h
@@ -117,12 +117,14 @@ struct sway_container {
struct wlr_texture *title_focused;
struct wlr_texture *title_focused_inactive;
+ struct wlr_texture *title_focused_tab_title;
struct wlr_texture *title_unfocused;
struct wlr_texture *title_urgent;
list_t *marks; // char *
struct wlr_texture *marks_focused;
struct wlr_texture *marks_focused_inactive;
+ struct wlr_texture *marks_focused_tab_title;
struct wlr_texture *marks_unfocused;
struct wlr_texture *marks_urgent;
diff --git a/include/sway/tree/root.h b/include/sway/tree/root.h
index e8f4d573..5d4a2f2d 100644
--- a/include/sway/tree/root.h
+++ b/include/sway/tree/root.h
@@ -31,7 +31,7 @@ struct sway_root {
list_t *scratchpad; // struct sway_container
// For when there's no connected outputs
- struct sway_output *noop_output;
+ struct sway_output *fallback_output;
struct sway_container *fullscreen_global;
diff --git a/include/swaynag/swaynag.h b/include/swaynag/swaynag.h
index 9e39e716..baa6ee8b 100644
--- a/include/swaynag/swaynag.h
+++ b/include/swaynag/swaynag.h
@@ -5,7 +5,6 @@
#include "list.h"
#include "pool-buffer.h"
#include "swaynag/types.h"
-#include "xdg-output-unstable-v1-client-protocol.h"
#define SWAYNAG_MAX_HEIGHT 500
@@ -75,13 +74,11 @@ struct swaynag_details {
struct swaynag {
bool run_display;
- int querying_outputs;
struct wl_display *display;
struct wl_compositor *compositor;
struct wl_seat *seat;
struct wl_shm *shm;
- struct zxdg_output_manager_v1 *xdg_output_manager;
struct wl_list outputs; // swaynag_output::link
struct wl_list seats; // swaynag_seat::link
struct swaynag_output *output;
diff --git a/meson.build b/meson.build
index 436b84d1..5e4de87f 100644
--- a/meson.build
+++ b/meson.build
@@ -1,9 +1,9 @@
project(
'sway',
'c',
- version: '1.6',
+ version: '1.7',
license: 'MIT',
- meson_version: '>=0.59.0',
+ meson_version: '>=0.60.0',
default_options: [
'c_std=c11',
'warning_level=2',
@@ -37,11 +37,11 @@ endif
jsonc = dependency('json-c', version: '>=0.13')
pcre = dependency('libpcre')
-wayland_server = dependency('wayland-server')
+wayland_server = dependency('wayland-server', version: '>=1.20.0')
wayland_client = dependency('wayland-client')
wayland_cursor = dependency('wayland-cursor')
wayland_egl = dependency('wayland-egl')
-wayland_protos = dependency('wayland-protocols', version: '>=1.14')
+wayland_protos = dependency('wayland-protocols', version: '>=1.24')
xkbcommon = dependency('xkbcommon')
cairo = dependency('cairo')
pango = dependency('pango')
@@ -92,18 +92,10 @@ if get_option('sd-bus-provider') == 'auto'
if not get_option('tray').disabled()
assert(get_option('auto_features').auto(), 'sd-bus-provider must not be set to auto since auto_features != auto')
endif
- sdbus = dependency('libsystemd',
+ sdbus = dependency(['libsystemd', 'libelogind'],
required: false,
version: '>=239',
- not_found_message: 'libsystemd not found, trying libelogind',
)
- if not sdbus.found()
- sdbus = dependency('libelogind',
- required: false,
- version: '>=239',
- not_found_message: 'libelogind not found, trying basu',
- )
- endif
if not sdbus.found()
sdbus = dependency('basu', required: false)
endif
@@ -171,8 +163,8 @@ add_project_arguments('-DSYSCONFDIR="/@0@"'.format(join_paths(prefix, sysconfdir
version = '"@0@"'.format(meson.project_version())
git = find_program('git', native: true, required: false)
if git.found()
- git_commit = run_command([git, 'rev-parse', '--short', 'HEAD'])
- git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD'])
+ git_commit = run_command([git, 'rev-parse', '--short', 'HEAD'], check: false)
+ git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD'], check: false)
if git_commit.returncode() == 0 and git_branch.returncode() == 0
version = '"@0@-@1@ (" __DATE__ ", branch \'@2@\')"'.format(
meson.project_version(),
diff --git a/protocols/meson.build b/protocols/meson.build
index 8e9e65be..df24a4e5 100644
--- a/protocols/meson.build
+++ b/protocols/meson.build
@@ -15,6 +15,7 @@ protocols = [
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/tablet/tablet-unstable-v2.xml'],
+ [wl_protocol_dir, 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml'],
['wlr-layer-shell-unstable-v1.xml'],
['idle.xml'],
['wlr-input-inhibitor-unstable-v1.xml'],
diff --git a/sway/commands.c b/sway/commands.c
index 205406ad..5a1fd32e 100644
--- a/sway/commands.c
+++ b/sway/commands.c
@@ -51,6 +51,7 @@ static const struct cmd_handler handlers[] = {
{ "client.background", cmd_client_noop },
{ "client.focused", cmd_client_focused },
{ "client.focused_inactive", cmd_client_focused_inactive },
+ { "client.focused_tab_title", cmd_client_focused_tab_title },
{ "client.placeholder", cmd_client_noop },
{ "client.unfocused", cmd_client_unfocused },
{ "client.urgent", cmd_client_urgent },
diff --git a/sway/commands/bar/hidden_state.c b/sway/commands/bar/hidden_state.c
index 1f08a5d2..8b661e3a 100644
--- a/sway/commands/bar/hidden_state.c
+++ b/sway/commands/bar/hidden_state.c
@@ -54,7 +54,7 @@ struct cmd_results *bar_cmd_hidden_state(int argc, char **argv) {
}
const char *state = argv[0];
- if (config->reading) {
+ if (config->current_bar) {
error = bar_set_hidden_state(config->current_bar, state);
} else {
const char *id = argc == 2 ? argv[1] : NULL;
diff --git a/sway/commands/bar/mode.c b/sway/commands/bar/mode.c
index 8b3fb275..7c2f423b 100644
--- a/sway/commands/bar/mode.c
+++ b/sway/commands/bar/mode.c
@@ -58,7 +58,7 @@ struct cmd_results *bar_cmd_mode(int argc, char **argv) {
}
const char *mode = argv[0];
- if (config->reading) {
+ if (config->current_bar) {
error = bar_set_mode(config->current_bar, mode);
} else {
const char *id = argc == 2 ? argv[1] : NULL;
diff --git a/sway/commands/client.c b/sway/commands/client.c
index dd0694df..77263145 100644
--- a/sway/commands/client.c
+++ b/sway/commands/client.c
@@ -18,6 +18,12 @@ static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name,
return error;
}
+ if (argc > 3 && strcmp(cmd_name, "client.focused_tab_title") == 0) {
+ sway_log(SWAY_ERROR,
+ "Warning: indicator and child_border colors have no effect for %s",
+ cmd_name);
+ }
+
struct border_colors colors = {0};
const char *ind_hex = argc > 3 ? argv[3] : default_indicator;
const char *child_hex = argc > 4 ? argv[4] : argv[1]; // def to background
@@ -80,3 +86,13 @@ struct cmd_results *cmd_client_noop(int argc, char **argv) {
sway_log(SWAY_INFO, "Warning: %s is ignored by sway", argv[-1]);
return cmd_results_new(CMD_SUCCESS, NULL);
}
+
+struct cmd_results *cmd_client_focused_tab_title(int argc, char **argv) {
+ struct cmd_results *result = handle_command(argc, argv,
+ "client.focused_tab_title",
+ &config->border_colors.focused_tab_title, "#2e9ef4ff");
+ if (result && result->status == CMD_SUCCESS) {
+ config->has_focused_tab_title = true;
+ }
+ return result;
+}
diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c
index fce337d5..b35065c1 100644
--- a/sway/commands/exec_always.c
+++ b/sway/commands/exec_always.c
@@ -7,6 +7,7 @@
#include
#include "sway/commands.h"
#include "sway/config.h"
+#include "sway/server.h"
#include "sway/tree/container.h"
#include "sway/tree/root.h"
#include "sway/tree/workspace.h"
@@ -53,6 +54,7 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) {
// Fork process
if ((pid = fork()) == 0) {
// Fork child process again
+ restore_nofile_limit();
setsid();
sigset_t set;
sigemptyset(&set);
diff --git a/sway/commands/focus.c b/sway/commands/focus.c
index 6771ca2f..b8d28480 100644
--- a/sway/commands/focus.c
+++ b/sway/commands/focus.c
@@ -267,6 +267,11 @@ static struct cmd_results *focus_mode(struct sway_workspace *ws,
new_focus = seat_get_focus_inactive_tiling(seat, ws);
}
if (new_focus) {
+ struct sway_container *new_focus_view =
+ seat_get_focus_inactive_view(seat, &new_focus->node);
+ if (new_focus_view) {
+ new_focus = new_focus_view;
+ }
seat_set_focus_container(seat, new_focus);
// If we're on the floating layer and the floating container area
@@ -446,7 +451,8 @@ struct cmd_results *cmd_focus(int argc, char **argv) {
return cmd_results_new(CMD_FAILURE, "");
}
struct sway_node *next_focus = NULL;
- if (container_is_floating(container)) {
+ if (container_is_floating(container) &&
+ container->pending.fullscreen_mode == FULLSCREEN_NONE) {
next_focus = node_get_in_direction_floating(container, seat, direction);
} else {
next_focus = node_get_in_direction_tiling(container, seat, direction, descend);
diff --git a/sway/commands/move.c b/sway/commands/move.c
index f2702fa1..1a05a7a6 100644
--- a/sway/commands/move.c
+++ b/sway/commands/move.c
@@ -874,6 +874,10 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) {
return cmd_results_new(CMD_INVALID, "Invalid x position specified");
}
+ if (argc < 1) {
+ return cmd_results_new(CMD_FAILURE, expected_position_syntax);
+ }
+
struct movement_amount ly = { .amount = 0, .unit = MOVEMENT_UNIT_INVALID };
// Y direction
num_consumed_args = parse_movement_amount(argc, argv, &ly);
diff --git a/sway/commands/output.c b/sway/commands/output.c
index d8ef2885..125df5a7 100644
--- a/sway/commands/output.c
+++ b/sway/commands/output.c
@@ -18,6 +18,7 @@ static const struct cmd_handler output_handlers[] = {
{ "modeline", output_cmd_modeline },
{ "pos", output_cmd_position },
{ "position", output_cmd_position },
+ { "render_bit_depth", output_cmd_render_bit_depth },
{ "res", output_cmd_mode },
{ "resolution", output_cmd_mode },
{ "scale", output_cmd_scale },
@@ -33,9 +34,9 @@ struct cmd_results *cmd_output(int argc, char **argv) {
return error;
}
- // The NOOP-1 output is a dummy output used when there's no outputs
+ // The HEADLESS-1 output is a dummy output used when there's no outputs
// connected. It should never be configured.
- if (strcasecmp(argv[0], root->noop_output->wlr_output->name) == 0) {
+ if (strcasecmp(argv[0], root->fallback_output->wlr_output->name) == 0) {
return cmd_results_new(CMD_FAILURE,
"Refusing to configure the no op output");
}
@@ -52,7 +53,7 @@ struct cmd_results *cmd_output(int argc, char **argv) {
if (!sway_output) {
return cmd_results_new(CMD_FAILURE, "Unknown output");
}
- if (sway_output == root->noop_output) {
+ if (sway_output == root->fallback_output) {
return cmd_results_new(CMD_FAILURE,
"Refusing to configure the no op output");
}
diff --git a/sway/commands/output/render_bit_depth.c b/sway/commands/output/render_bit_depth.c
new file mode 100644
index 00000000..c419321e
--- /dev/null
+++ b/sway/commands/output/render_bit_depth.c
@@ -0,0 +1,29 @@
+#include
+#include
+#include "sway/commands.h"
+#include "sway/config.h"
+
+struct cmd_results *output_cmd_render_bit_depth(int argc, char **argv) {
+ if (!config->handler_context.output_config) {
+ return cmd_results_new(CMD_FAILURE, "Missing output config");
+ }
+ if (!argc) {
+ return cmd_results_new(CMD_INVALID, "Missing bit depth argument.");
+ }
+
+ if (strcmp(*argv, "8") == 0) {
+ config->handler_context.output_config->render_bit_depth =
+ RENDER_BIT_DEPTH_8;
+ } else if (strcmp(*argv, "10") == 0) {
+ config->handler_context.output_config->render_bit_depth =
+ RENDER_BIT_DEPTH_10;
+ } else {
+ return cmd_results_new(CMD_INVALID,
+ "Invalid bit depth. Must be a value in (8|10).");
+ }
+
+ config->handler_context.leftovers.argc = argc - 1;
+ config->handler_context.leftovers.argv = argv + 1;
+ return NULL;
+}
+
diff --git a/sway/commands/smart_gaps.c b/sway/commands/smart_gaps.c
index b27f9ccd..a6d165dc 100644
--- a/sway/commands/smart_gaps.c
+++ b/sway/commands/smart_gaps.c
@@ -15,7 +15,12 @@ struct cmd_results *cmd_smart_gaps(int argc, char **argv) {
return error;
}
- config->smart_gaps = parse_boolean(argv[0], config->smart_gaps);
+ if (strcmp(argv[0], "inverse_outer") == 0) {
+ config->smart_gaps = SMART_GAPS_INVERSE_OUTER;
+ } else {
+ config->smart_gaps = parse_boolean(argv[0], config->smart_gaps)
+ ? SMART_GAPS_ON : SMART_GAPS_OFF;
+ }
arrange_root();
diff --git a/sway/commands/swap.c b/sway/commands/swap.c
index ce5e5128..9355944d 100644
--- a/sway/commands/swap.c
+++ b/sway/commands/swap.c
@@ -126,10 +126,10 @@ void container_swap(struct sway_container *con1, struct sway_container *con2) {
}
enum sway_fullscreen_mode fs1 = con1->pending.fullscreen_mode;
- enum sway_fullscreen_mode fs2 = con2->pending.fullscreen_mode;
if (fs1) {
container_fullscreen_disable(con1);
}
+ enum sway_fullscreen_mode fs2 = con2->pending.fullscreen_mode;
if (fs2) {
container_fullscreen_disable(con2);
}
@@ -247,6 +247,9 @@ struct cmd_results *cmd_swap(int argc, char **argv) {
} else if (!current) {
error = cmd_results_new(CMD_FAILURE,
"Can only swap with containers and views");
+ } else if (current == other) {
+ error = cmd_results_new(CMD_FAILURE,
+ "Cannot swap a container with itself");
} else if (container_has_ancestor(current, other)
|| container_has_ancestor(other, current)) {
error = cmd_results_new(CMD_FAILURE,
diff --git a/sway/config.c b/sway/config.c
index e3daacda..e4745a5c 100644
--- a/sway/config.c
+++ b/sway/config.c
@@ -266,7 +266,7 @@ static void config_defaults(struct sway_config *config) {
config->tiling_drag = true;
config->tiling_drag_threshold = 9;
- config->smart_gaps = false;
+ config->smart_gaps = SMART_GAPS_OFF;
config->gaps_inner = 0;
config->gaps_outer.top = 0;
config->gaps_outer.right = 0;
@@ -290,6 +290,8 @@ static void config_defaults(struct sway_config *config) {
config->hide_edge_borders_smart = ESMART_OFF;
config->hide_lone_tab = false;
+ config->has_focused_tab_title = false;
+
// border colors
color_to_rgba(config->border_colors.focused.border, 0x4C7899FF);
color_to_rgba(config->border_colors.focused.background, 0x285577FF);
diff --git a/sway/config/bar.c b/sway/config/bar.c
index e09add44..d1b342e6 100644
--- a/sway/config/bar.c
+++ b/sway/config/bar.c
@@ -219,6 +219,8 @@ static void invoke_swaybar(struct bar_config *bar) {
sigprocmask(SIG_SETMASK, &set, NULL);
signal(SIGPIPE, SIG_DFL);
+ restore_nofile_limit();
+
pid = fork();
if (pid < 0) {
sway_log_errno(SWAY_ERROR, "fork failed");
diff --git a/sway/config/output.c b/sway/config/output.c
index 8e937b28..fa509252 100644
--- a/sway/config/output.c
+++ b/sway/config/output.c
@@ -1,5 +1,6 @@
#define _POSIX_C_SOURCE 200809L
#include
+#include
#include
#include
#include
@@ -67,6 +68,7 @@ struct output_config *new_output_config(const char *name) {
oc->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
oc->max_render_time = -1;
oc->adaptive_sync = -1;
+ oc->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT;
return oc;
}
@@ -113,6 +115,9 @@ void merge_output_config(struct output_config *dst, struct output_config *src) {
if (src->adaptive_sync != -1) {
dst->adaptive_sync = src->adaptive_sync;
}
+ if (src->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
+ dst->render_bit_depth = src->render_bit_depth;
+ }
if (src->background) {
free(dst->background);
dst->background = strdup(src->background);
@@ -351,9 +356,26 @@ static int compute_default_scale(struct wlr_output *output) {
return 2;
}
+/* Lists of formats to try, in order, when a specific render bit depth has
+ * been asked for. The second to last format in each list should always
+ * be XRGB8888, as a reliable backup in case the others are not available;
+ * the last should be DRM_FORMAT_INVALID, to indicate the end of the list. */
+static const uint32_t *bit_depth_preferences[] = {
+ [RENDER_BIT_DEPTH_8] = (const uint32_t []){
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_INVALID,
+ },
+ [RENDER_BIT_DEPTH_10] = (const uint32_t []){
+ DRM_FORMAT_XRGB2101010,
+ DRM_FORMAT_XBGR2101010,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_INVALID,
+ },
+};
+
static void queue_output_config(struct output_config *oc,
struct sway_output *output) {
- if (output == root->noop_output) {
+ if (output == root->fallback_output) {
return;
}
@@ -437,10 +459,26 @@ static void queue_output_config(struct output_config *oc,
oc->adaptive_sync);
wlr_output_enable_adaptive_sync(wlr_output, oc->adaptive_sync == 1);
}
+
+ if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
+ const uint32_t *fmts = bit_depth_preferences[oc->render_bit_depth];
+ assert(fmts);
+
+ for (size_t i = 0; fmts[i] != DRM_FORMAT_INVALID; i++) {
+ wlr_output_set_render_format(wlr_output, fmts[i]);
+ if (wlr_output_test(wlr_output)) {
+ break;
+ }
+
+ sway_log(SWAY_DEBUG, "Preferred output format 0x%08x "
+ "failed to work, falling back to next in "
+ "list, 0x%08x", fmts[i], fmts[i + 1]);
+ }
+ }
}
bool apply_output_config(struct output_config *oc, struct sway_output *output) {
- if (output == root->noop_output) {
+ if (output == root->fallback_output) {
return false;
}
@@ -535,7 +573,7 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
}
bool test_output_config(struct output_config *oc, struct sway_output *output) {
- if (output == root->noop_output) {
+ if (output == root->fallback_output) {
return false;
}
@@ -750,6 +788,8 @@ static bool _spawn_swaybg(char **command) {
sway_log_errno(SWAY_ERROR, "fork failed");
return false;
} else if (pid == 0) {
+ restore_nofile_limit();
+
pid = fork();
if (pid < 0) {
sway_log_errno(SWAY_ERROR, "fork failed");
diff --git a/sway/desktop/layer_shell.c b/sway/desktop/layer_shell.c
index 7f5a337b..27e457f1 100644
--- a/sway/desktop/layer_shell.c
+++ b/sway/desktop/layer_shell.c
@@ -352,6 +352,8 @@ static void unmap(struct sway_layer_surface *sway_layer) {
sway_layer->layer_surface->surface, true);
}
+static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface);
+
static void handle_destroy(struct wl_listener *listener, void *data) {
struct sway_layer_surface *sway_layer =
wl_container_of(listener, sway_layer, destroy);
@@ -360,6 +362,12 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
if (sway_layer->layer_surface->mapped) {
unmap(sway_layer);
}
+
+ struct sway_layer_subsurface *subsurface, *subsurface_tmp;
+ wl_list_for_each_safe(subsurface, subsurface_tmp, &sway_layer->subsurfaces, link) {
+ layer_subsurface_destroy(subsurface);
+ }
+
wl_list_remove(&sway_layer->link);
wl_list_remove(&sway_layer->destroy.link);
wl_list_remove(&sway_layer->map.link);
@@ -428,11 +436,8 @@ static void subsurface_handle_commit(struct wl_listener *listener, void *data) {
subsurface_damage(subsurface, false);
}
-static void subsurface_handle_destroy(struct wl_listener *listener,
- void *data) {
- struct sway_layer_subsurface *subsurface =
- wl_container_of(listener, subsurface, destroy);
-
+static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface) {
+ wl_list_remove(&subsurface->link);
wl_list_remove(&subsurface->map.link);
wl_list_remove(&subsurface->unmap.link);
wl_list_remove(&subsurface->destroy.link);
@@ -440,6 +445,13 @@ static void subsurface_handle_destroy(struct wl_listener *listener,
free(subsurface);
}
+static void subsurface_handle_destroy(struct wl_listener *listener,
+ void *data) {
+ struct sway_layer_subsurface *subsurface =
+ wl_container_of(listener, subsurface, destroy);
+ layer_subsurface_destroy(subsurface);
+}
+
static struct sway_layer_subsurface *create_subsurface(
struct wlr_subsurface *wlr_subsurface,
struct sway_layer_surface *layer_surface) {
@@ -451,6 +463,7 @@ static struct sway_layer_subsurface *create_subsurface(
subsurface->wlr_subsurface = wlr_subsurface;
subsurface->layer_surface = layer_surface;
+ wl_list_insert(&layer_surface->subsurfaces, &subsurface->link);
subsurface->map.notify = subsurface_handle_map;
wl_signal_add(&wlr_subsurface->events.map, &subsurface->map);
@@ -624,7 +637,7 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
output = ws->output;
}
}
- if (!output || output == root->noop_output) {
+ if (!output || output == root->fallback_output) {
if (!root->outputs->length) {
sway_log(SWAY_ERROR,
"no output to auto-assign layer surface '%s' to",
@@ -643,6 +656,8 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
return;
}
+ wl_list_init(&sway_layer->subsurfaces);
+
sway_layer->surface_commit.notify = handle_surface_commit;
wl_signal_add(&layer_surface->surface->events.commit,
&sway_layer->surface_commit);
@@ -664,7 +679,7 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
struct sway_output *output = layer_surface->output->data;
sway_layer->output_destroy.notify = handle_output_destroy;
- wl_signal_add(&output->events.destroy, &sway_layer->output_destroy);
+ wl_signal_add(&output->events.disable, &sway_layer->output_destroy);
wl_list_insert(&output->layers[layer_surface->pending.layer],
&sway_layer->link);
diff --git a/sway/desktop/output.c b/sway/desktop/output.c
index edec71ad..68f095c0 100644
--- a/sway/desktop/output.c
+++ b/sway/desktop/output.c
@@ -5,6 +5,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -633,21 +634,19 @@ static void damage_surface_iterator(struct sway_output *output,
struct wlr_box box = *_box;
scale_box(&box, output->wlr_output->scale);
- if (pixman_region32_not_empty(&surface->buffer_damage)) {
- pixman_region32_t damage;
- pixman_region32_init(&damage);
- wlr_surface_get_effective_damage(surface, &damage);
- wlr_region_scale(&damage, &damage, output->wlr_output->scale);
- if (ceil(output->wlr_output->scale) > surface->current.scale) {
- // When scaling up a surface, it'll become blurry so we need to
- // expand the damage region
- wlr_region_expand(&damage, &damage,
- ceil(output->wlr_output->scale) - surface->current.scale);
- }
- pixman_region32_translate(&damage, box.x, box.y);
- wlr_output_damage_add(output->damage, &damage);
- pixman_region32_fini(&damage);
+ pixman_region32_t damage;
+ pixman_region32_init(&damage);
+ wlr_surface_get_effective_damage(surface, &damage);
+ wlr_region_scale(&damage, &damage, output->wlr_output->scale);
+ if (ceil(output->wlr_output->scale) > surface->current.scale) {
+ // When scaling up a surface, it'll become blurry so we need to
+ // expand the damage region
+ wlr_region_expand(&damage, &damage,
+ ceil(output->wlr_output->scale) - surface->current.scale);
}
+ pixman_region32_translate(&damage, box.x, box.y);
+ wlr_output_damage_add(output->damage, &damage);
+ pixman_region32_fini(&damage);
if (whole) {
wlr_output_damage_add_box(output->damage, &box);
@@ -733,7 +732,7 @@ static void update_output_manager_config(struct sway_server *server) {
struct sway_output *output;
wl_list_for_each(output, &root->all_outputs, link) {
- if (output == root->noop_output) {
+ if (output == root->fallback_output) {
continue;
}
struct wlr_output_configuration_head_v1 *config_head =
@@ -755,18 +754,22 @@ static void update_output_manager_config(struct sway_server *server) {
static void handle_destroy(struct wl_listener *listener, void *data) {
struct sway_output *output = wl_container_of(listener, output, destroy);
struct sway_server *server = output->server;
- wl_signal_emit(&output->events.destroy, output);
+ output_begin_destroy(output);
if (output->enabled) {
output_disable(output);
}
- output_begin_destroy(output);
+
+ wl_list_remove(&output->link);
wl_list_remove(&output->destroy.link);
wl_list_remove(&output->commit.link);
wl_list_remove(&output->mode.link);
wl_list_remove(&output->present.link);
+ output->wlr_output->data = NULL;
+ output->wlr_output = NULL;
+
transaction_commit_dirty();
update_output_manager_config(server);
@@ -835,9 +838,22 @@ static void handle_present(struct wl_listener *listener, void *data) {
output->refresh_nsec = output_event->refresh;
}
+static unsigned int last_headless_num = 0;
+
void handle_new_output(struct wl_listener *listener, void *data) {
struct sway_server *server = wl_container_of(listener, server, new_output);
struct wlr_output *wlr_output = data;
+
+ if (wlr_output == root->fallback_output->wlr_output) {
+ return;
+ }
+
+ if (wlr_output_is_headless(wlr_output)) {
+ char name[64];
+ snprintf(name, sizeof(name), "HEADLESS-%u", ++last_headless_num);
+ wlr_output_set_name(wlr_output, name);
+ }
+
sway_log(SWAY_DEBUG, "New output %p: %s (non-desktop: %d)",
wlr_output, wlr_output->name, wlr_output->non_desktop);
@@ -850,6 +866,12 @@ void handle_new_output(struct wl_listener *listener, void *data) {
return;
}
+ if (!wlr_output_init_render(wlr_output, server->allocator,
+ server->renderer)) {
+ sway_log(SWAY_ERROR, "Failed to init output render");
+ return;
+ }
+
struct sway_output *output = output_create(wlr_output);
if (!output) {
return;
diff --git a/sway/desktop/render.c b/sway/desktop/render.c
index 17fc8f6f..c088c936 100644
--- a/sway/desktop/render.c
+++ b/sway/desktop/render.c
@@ -52,7 +52,7 @@ static int scale_length(int length, int offset, float scale) {
static void scissor_output(struct wlr_output *wlr_output,
pixman_box32_t *rect) {
- struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend);
+ struct wlr_renderer *renderer = wlr_output->renderer;
assert(renderer);
struct wlr_box box = {
@@ -100,8 +100,7 @@ static void render_texture(struct wlr_output *wlr_output,
pixman_region32_t *output_damage, struct wlr_texture *texture,
const struct wlr_fbox *src_box, const struct wlr_box *dst_box,
const float matrix[static 9], float alpha) {
- struct wlr_renderer *renderer =
- wlr_backend_get_renderer(wlr_output->backend);
+ struct wlr_renderer *renderer = wlr_output->renderer;
struct sway_output *output = wlr_output->data;
pixman_region32_t damage;
@@ -218,8 +217,7 @@ void render_rect(struct sway_output *output,
pixman_region32_t *output_damage, const struct wlr_box *_box,
float color[static 4]) {
struct wlr_output *wlr_output = output->wlr_output;
- struct wlr_renderer *renderer =
- wlr_backend_get_renderer(wlr_output->backend);
+ struct wlr_renderer *renderer = wlr_output->renderer;
struct wlr_box box;
memcpy(&box, _box, sizeof(struct wlr_box));
@@ -764,6 +762,14 @@ static void render_containers_linear(struct sway_output *output,
}
}
+static bool container_is_focused(struct sway_container *con, void *data) {
+ return con->current.focused;
+}
+
+static bool container_has_focused_child(struct sway_container *con) {
+ return container_find_child(con, container_is_focused, NULL);
+}
+
/**
* Render a container's children using the L_TABBED layout.
*/
@@ -795,6 +801,10 @@ static void render_containers_tabbed(struct sway_output *output,
colors = &config->border_colors.focused;
title_texture = child->title_focused;
marks_texture = child->marks_focused;
+ } else if (config->has_focused_tab_title && container_has_focused_child(child)) {
+ colors = &config->border_colors.focused_tab_title;
+ title_texture = child->title_focused_tab_title;
+ marks_texture = child->marks_focused_tab_title;
} else if (child == parent->active_child) {
colors = &config->border_colors.focused_inactive;
title_texture = child->title_focused_inactive;
@@ -860,7 +870,11 @@ static void render_containers_stacked(struct sway_output *output,
colors = &config->border_colors.focused;
title_texture = child->title_focused;
marks_texture = child->marks_focused;
- } else if (child == parent->active_child) {
+ } else if (config->has_focused_tab_title && container_has_focused_child(child)) {
+ colors = &config->border_colors.focused_tab_title;
+ title_texture = child->title_focused_tab_title;
+ marks_texture = child->marks_focused_tab_title;
+ } else if (child == parent->active_child) {
colors = &config->border_colors.focused_inactive;
title_texture = child->title_focused_inactive;
marks_texture = child->marks_focused_inactive;
@@ -1013,13 +1027,7 @@ static void render_seatops(struct sway_output *output,
void output_render(struct sway_output *output, struct timespec *when,
pixman_region32_t *damage) {
struct wlr_output *wlr_output = output->wlr_output;
-
- struct wlr_renderer *renderer =
- wlr_backend_get_renderer(wlr_output->backend);
- if (!sway_assert(renderer != NULL,
- "expected the output backend to have a renderer")) {
- return;
- }
+ struct wlr_renderer *renderer = output->server->renderer;
struct sway_workspace *workspace = output->current.active_workspace;
if (workspace == NULL) {
diff --git a/sway/desktop/transaction.c b/sway/desktop/transaction.c
index b1f3fb32..f5a3a053 100644
--- a/sway/desktop/transaction.c
+++ b/sway/desktop/transaction.c
@@ -402,7 +402,7 @@ static void transaction_commit(struct sway_transaction *transaction) {
struct sway_transaction_instruction *instruction =
transaction->instructions->items[i];
struct sway_node *node = instruction->node;
- bool hidden = node_is_view(node) &&
+ bool hidden = node_is_view(node) && !node->destroying &&
!view_is_visible(node->sway_container->view);
if (should_configure(node, instruction)) {
instruction->serial = view_configure(node->sway_container->view,
diff --git a/sway/desktop/xdg_shell.c b/sway/desktop/xdg_shell.c
index c1e5bc68..5fae8296 100644
--- a/sway/desktop/xdg_shell.c
+++ b/sway/desktop/xdg_shell.c
@@ -72,8 +72,8 @@ static void popup_unconstrain(struct sway_xdg_popup *popup) {
// the output box expressed in the coordinate system of the toplevel parent
// of the popup
struct wlr_box output_toplevel_sx_box = {
- .x = output->lx - view->container->pending.content_x,
- .y = output->ly - view->container->pending.content_y,
+ .x = output->lx - view->container->pending.content_x + view->geometry.x,
+ .y = output->ly - view->container->pending.content_y + view->geometry.y,
.width = output->width,
.height = output->height,
};
diff --git a/sway/desktop/xwayland.c b/sway/desktop/xwayland.c
index 1af8d248..40288f97 100644
--- a/sway/desktop/xwayland.c
+++ b/sway/desktop/xwayland.c
@@ -436,6 +436,8 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&xwayland_view->commit.link);
}
+ xwayland_view->view.wlr_xwayland_surface = NULL;
+
wl_list_remove(&xwayland_view->destroy.link);
wl_list_remove(&xwayland_view->request_configure.link);
wl_list_remove(&xwayland_view->request_fullscreen.link);
diff --git a/sway/input/cursor.c b/sway/input/cursor.c
index 1e3e16d6..6fddee90 100644
--- a/sway/input/cursor.c
+++ b/sway/input/cursor.c
@@ -83,7 +83,28 @@ static struct wlr_surface *layer_surface_popup_at(struct sway_output *output,
struct sway_node *node_at_coords(
struct sway_seat *seat, double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy) {
- // check for unmanaged views first
+ // find the output the cursor is on
+ struct wlr_output *wlr_output = wlr_output_layout_output_at(
+ root->output_layout, lx, ly);
+ if (wlr_output == NULL) {
+ return NULL;
+ }
+ struct sway_output *output = wlr_output->data;
+ if (!output || !output->enabled) {
+ // output is being destroyed or is being enabled
+ return NULL;
+ }
+ double ox = lx, oy = ly;
+ wlr_output_layout_output_coords(root->output_layout, wlr_output, &ox, &oy);
+
+ // layer surfaces on the overlay layer are rendered on top
+ if ((*surface = layer_surface_at(output,
+ &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
+ ox, oy, sx, sy))) {
+ return NULL;
+ }
+
+ // check for unmanaged views
#if HAVE_XWAYLAND
struct wl_list *unmanaged = &root->xwayland_unmanaged;
struct sway_xwayland_unmanaged *unmanaged_surface;
@@ -101,19 +122,6 @@ struct sway_node *node_at_coords(
}
}
#endif
- // find the output the cursor is on
- struct wlr_output *wlr_output = wlr_output_layout_output_at(
- root->output_layout, lx, ly);
- if (wlr_output == NULL) {
- return NULL;
- }
- struct sway_output *output = wlr_output->data;
- if (!output || !output->enabled) {
- // output is being destroyed or is being enabled
- return NULL;
- }
- double ox = lx, oy = ly;
- wlr_output_layout_output_coords(root->output_layout, wlr_output, &ox, &oy);
if (root->fullscreen_global) {
// Try fullscreen container
@@ -131,11 +139,6 @@ struct sway_node *node_at_coords(
return NULL;
}
- if ((*surface = layer_surface_at(output,
- &output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY],
- ox, oy, sx, sy))) {
- return NULL;
- }
if (ws->fullscreen) {
// Try transient containers
for (int i = 0; i < ws->floating->length; ++i) {
@@ -924,6 +927,7 @@ static void handle_pointer_pinch_begin(struct wl_listener *listener, void *data)
struct sway_cursor *cursor = wl_container_of(
listener, cursor, pinch_begin);
struct wlr_event_pointer_pinch_begin *event = data;
+ cursor_handle_activity_from_device(cursor, event->device);
wlr_pointer_gestures_v1_send_pinch_begin(
cursor->pointer_gestures, cursor->seat->wlr_seat,
event->time_msec, event->fingers);
@@ -933,6 +937,7 @@ static void handle_pointer_pinch_update(struct wl_listener *listener, void *data
struct sway_cursor *cursor = wl_container_of(
listener, cursor, pinch_update);
struct wlr_event_pointer_pinch_update *event = data;
+ cursor_handle_activity_from_device(cursor, event->device);
wlr_pointer_gestures_v1_send_pinch_update(
cursor->pointer_gestures, cursor->seat->wlr_seat,
event->time_msec, event->dx, event->dy,
@@ -943,6 +948,7 @@ static void handle_pointer_pinch_end(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(
listener, cursor, pinch_end);
struct wlr_event_pointer_pinch_end *event = data;
+ cursor_handle_activity_from_device(cursor, event->device);
wlr_pointer_gestures_v1_send_pinch_end(
cursor->pointer_gestures, cursor->seat->wlr_seat,
event->time_msec, event->cancelled);
@@ -952,6 +958,7 @@ static void handle_pointer_swipe_begin(struct wl_listener *listener, void *data)
struct sway_cursor *cursor = wl_container_of(
listener, cursor, swipe_begin);
struct wlr_event_pointer_swipe_begin *event = data;
+ cursor_handle_activity_from_device(cursor, event->device);
wlr_pointer_gestures_v1_send_swipe_begin(
cursor->pointer_gestures, cursor->seat->wlr_seat,
event->time_msec, event->fingers);
@@ -961,6 +968,7 @@ static void handle_pointer_swipe_update(struct wl_listener *listener, void *data
struct sway_cursor *cursor = wl_container_of(
listener, cursor, swipe_update);
struct wlr_event_pointer_swipe_update *event = data;
+ cursor_handle_activity_from_device(cursor, event->device);
wlr_pointer_gestures_v1_send_swipe_update(
cursor->pointer_gestures, cursor->seat->wlr_seat,
event->time_msec, event->dx, event->dy);
@@ -970,6 +978,7 @@ static void handle_pointer_swipe_end(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(
listener, cursor, swipe_end);
struct wlr_event_pointer_swipe_end *event = data;
+ cursor_handle_activity_from_device(cursor, event->device);
wlr_pointer_gestures_v1_send_swipe_end(
cursor->pointer_gestures, cursor->seat->wlr_seat,
event->time_msec, event->cancelled);
diff --git a/sway/input/seat.c b/sway/input/seat.c
index c5c8459e..ce933b66 100644
--- a/sway/input/seat.c
+++ b/sway/input/seat.c
@@ -51,6 +51,16 @@ static void seat_device_destroy(struct sway_seat_device *seat_device) {
static void seat_node_destroy(struct sway_seat_node *seat_node) {
wl_list_remove(&seat_node->destroy.link);
wl_list_remove(&seat_node->link);
+
+ /*
+ * This is the only time we remove items from the focus stack without
+ * immediately re-adding them. If we just removed the last thing,
+ * mark that nothing has focus anymore.
+ */
+ if (wl_list_empty(&seat_node->seat->focus_stack)) {
+ seat_node->seat->has_focus = false;
+ }
+
free(seat_node);
}
@@ -1415,9 +1425,8 @@ struct sway_node *seat_get_focus(struct sway_seat *seat) {
if (!seat->has_focus) {
return NULL;
}
- if (wl_list_empty(&seat->focus_stack)) {
- return NULL;
- }
+ sway_assert(!wl_list_empty(&seat->focus_stack),
+ "focus_stack is empty, but has_focus is true");
struct sway_seat_node *current =
wl_container_of(seat->focus_stack.next, current, link);
return current->node;
diff --git a/sway/input/seatop_resize_floating.c b/sway/input/seatop_resize_floating.c
index 8400a4b3..df683026 100644
--- a/sway/input/seatop_resize_floating.c
+++ b/sway/input/seatop_resize_floating.c
@@ -80,17 +80,25 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
double height = e->ref_height + grow_height;
int min_width, max_width, min_height, max_height;
floating_calculate_constraints(&min_width, &max_width,
- &min_height, &max_height);
- width = fmax(min_width + border_width, fmin(width, max_width));
- height = fmax(min_height + border_height, fmin(height, max_height));
+ &min_height, &max_height);
+ width = fmin(width, max_width - border_width);
+ width = fmax(width, min_width + border_width);
+ width = fmax(width, 1);
+ height = fmin(height, max_height - border_height);
+ height = fmax(height, min_height + border_height);
+ height = fmax(height, 1);
// Apply the view's min/max size
if (con->view) {
double view_min_width, view_max_width, view_min_height, view_max_height;
view_get_constraints(con->view, &view_min_width, &view_max_width,
&view_min_height, &view_max_height);
- width = fmax(view_min_width + border_width, fmin(width, view_max_width));
- height = fmax(view_min_height + border_height, fmin(height, view_max_height));
+ width = fmin(width, view_max_width - border_width);
+ width = fmax(width, view_min_width + border_width);
+ width = fmax(width, 1);
+ height = fmin(height, view_max_height - border_height);
+ height = fmax(height, view_min_height + border_height);
+ height = fmax(height, 1);
}
diff --git a/sway/ipc-server.c b/sway/ipc-server.c
index aad9a7b5..1bf5a05f 100644
--- a/sway/ipc-server.c
+++ b/sway/ipc-server.c
@@ -687,7 +687,7 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
}
struct sway_output *output;
wl_list_for_each(output, &root->all_outputs, link) {
- if (!output->enabled && output != root->noop_output) {
+ if (!output->enabled && output != root->fallback_output) {
json_object_array_add(outputs,
ipc_json_describe_disabled_output(output));
}
diff --git a/sway/main.c b/sway/main.c
index e960c4e2..b6f8a8bf 100644
--- a/sway/main.c
+++ b/sway/main.c
@@ -6,6 +6,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -27,6 +28,7 @@
static bool terminate_request = false;
static int exit_value = 0;
+static struct rlimit original_nofile_rlimit = {0};
struct sway_server server = {0};
struct sway_debug debug = {0};
@@ -63,7 +65,7 @@ void detect_proprietary(int allow_unsupported_gpu) {
sway_log(SWAY_ERROR,
"Proprietary Nvidia drivers are NOT supported. "
"Use Nouveau. To launch sway anyway, launch with "
- "--my-next-gpu-wont-be-nvidia and DO NOT report issues.");
+ "--unsupported-gpu and DO NOT report issues.");
exit(EXIT_FAILURE);
}
break;
@@ -151,6 +153,9 @@ static void log_kernel(void) {
static bool drop_permissions(void) {
if (getuid() != geteuid() || getgid() != getegid()) {
+ sway_log(SWAY_ERROR, "!!! DEPRECATION WARNING: "
+ "SUID privilege drop will be removed in a future release, please migrate to seatd-launch");
+
// Set the gid and uid in the correct order.
if (setgid(getgid()) != 0) {
sway_log(SWAY_ERROR, "Unable to drop root group, refusing to start");
@@ -169,6 +174,33 @@ static bool drop_permissions(void) {
return true;
}
+static void increase_nofile_limit(void) {
+ if (getrlimit(RLIMIT_NOFILE, &original_nofile_rlimit) != 0) {
+ sway_log_errno(SWAY_ERROR, "Failed to bump max open files limit: "
+ "getrlimit(NOFILE) failed");
+ return;
+ }
+
+ struct rlimit new_rlimit = original_nofile_rlimit;
+ new_rlimit.rlim_cur = new_rlimit.rlim_max;
+ if (setrlimit(RLIMIT_NOFILE, &new_rlimit) != 0) {
+ sway_log_errno(SWAY_ERROR, "Failed to bump max open files limit: "
+ "setrlimit(NOFILE) failed");
+ sway_log(SWAY_INFO, "Running with %d max open files",
+ (int)original_nofile_rlimit.rlim_cur);
+ }
+}
+
+void restore_nofile_limit(void) {
+ if (original_nofile_rlimit.rlim_cur == 0) {
+ return;
+ }
+ if (setrlimit(RLIMIT_NOFILE, &original_nofile_rlimit) != 0) {
+ sway_log_errno(SWAY_ERROR, "Failed to restore max open files limit: "
+ "setrlimit(NOFILE) failed");
+ }
+}
+
void enable_debug_flag(const char *flag) {
if (strcmp(flag, "damage=highlight") == 0) {
debug.damage = DAMAGE_HIGHLIGHT;
@@ -220,7 +252,6 @@ int main(int argc, char **argv) {
{"verbose", no_argument, NULL, 'V'},
{"get-socketpath", no_argument, NULL, 'p'},
{"unsupported-gpu", no_argument, NULL, 'u'},
- {"my-next-gpu-wont-be-nvidia", no_argument, NULL, 'u'},
{0, 0, 0, 0}
};
@@ -314,7 +345,6 @@ int main(int argc, char **argv) {
log_kernel();
log_distro();
log_env();
- detect_proprietary(allow_unsupported_gpu);
if (optind < argc) { // Behave as IPC client
if (optind != 1) {
@@ -341,6 +371,8 @@ int main(int argc, char **argv) {
return 0;
}
+ detect_proprietary(allow_unsupported_gpu);
+
if (!server_privileged_prepare(&server)) {
return 1;
}
@@ -350,6 +382,8 @@ int main(int argc, char **argv) {
exit(EXIT_FAILURE);
}
+ increase_nofile_limit();
+
// handle SIGTERM signals
signal(SIGTERM, sig_handler);
signal(SIGINT, sig_handler);
diff --git a/sway/meson.build b/sway/meson.build
index 1402db15..8eab31a2 100644
--- a/sway/meson.build
+++ b/sway/meson.build
@@ -188,6 +188,7 @@ sway_sources = files(
'commands/output/max_render_time.c',
'commands/output/mode.c',
'commands/output/position.c',
+ 'commands/output/render_bit_depth.c',
'commands/output/scale.c',
'commands/output/scale_filter.c',
'commands/output/subpixel.c',
diff --git a/sway/server.c b/sway/server.c
index b187fcd5..f50a0987 100644
--- a/sway/server.c
+++ b/sway/server.c
@@ -7,17 +7,18 @@
#include
#include
#include
-#include
#include
#include
#include
#include
#include
#include
+#include
#include
#include
#include
#include
+#include
#include
#include
#include
@@ -73,12 +74,29 @@ static void handle_drm_lease_request(struct wl_listener *listener, void *data) {
bool server_init(struct sway_server *server) {
sway_log(SWAY_DEBUG, "Initializing Wayland server");
- struct wlr_renderer *renderer = wlr_backend_get_renderer(server->backend);
- assert(renderer);
+ server->renderer = wlr_renderer_autocreate(server->backend);
+ if (!server->renderer) {
+ sway_log(SWAY_ERROR, "Failed to create renderer");
+ return false;
+ }
- wlr_renderer_init_wl_display(renderer, server->wl_display);
+ wlr_renderer_init_wl_shm(server->renderer, server->wl_display);
- server->compositor = wlr_compositor_create(server->wl_display, renderer);
+ if (wlr_renderer_get_dmabuf_texture_formats(server->renderer) != NULL) {
+ wlr_drm_create(server->wl_display, server->renderer);
+ server->linux_dmabuf_v1 =
+ wlr_linux_dmabuf_v1_create(server->wl_display, server->renderer);
+ }
+
+ server->allocator = wlr_allocator_autocreate(server->backend,
+ server->renderer);
+ if (!server->allocator) {
+ sway_log(SWAY_ERROR, "Failed to create allocator");
+ return false;
+ }
+
+ server->compositor = wlr_compositor_create(server->wl_display,
+ server->renderer);
server->compositor_new_surface.notify = handle_compositor_new_surface;
wl_signal_add(&server->compositor->events.new_surface,
&server->compositor_new_surface);
@@ -206,20 +224,20 @@ bool server_init(struct sway_server *server) {
return false;
}
- server->noop_backend = wlr_noop_backend_create(server->wl_display);
-
- struct wlr_output *wlr_output = wlr_noop_add_output(server->noop_backend);
- root->noop_output = output_create(wlr_output);
-
- server->headless_backend =
- wlr_headless_backend_create_with_renderer(server->wl_display, renderer);
+ server->headless_backend = wlr_headless_backend_create(server->wl_display);
if (!server->headless_backend) {
- sway_log(SWAY_INFO, "Failed to create secondary headless backend, "
- "starting without it");
+ sway_log(SWAY_ERROR, "Failed to create secondary headless backend");
+ wlr_backend_destroy(server->backend);
+ return false;
} else {
wlr_multi_backend_add(server->backend, server->headless_backend);
}
+ struct wlr_output *wlr_output =
+ wlr_headless_add_output(server->headless_backend, 800, 600);
+ wlr_output_set_name(wlr_output, "FALLBACK");
+ root->fallback_output = output_create(wlr_output);
+
// This may have been set already via -Dtxn-timeout
if (!server->txn_timeout_ms) {
server->txn_timeout_ms = 200;
@@ -276,6 +294,7 @@ bool server_start(struct sway_server *server) {
wlr_backend_destroy(server->backend);
return false;
}
+
return true;
}
diff --git a/sway/sway-output.5.scd b/sway/sway-output.5.scd
index 55d8f719..4159a851 100644
--- a/sway/sway-output.5.scd
+++ b/sway/sway-output.5.scd
@@ -157,6 +157,21 @@ must be separated by one space. For example:
adaptive sync can improve latency, but can cause flickering on some
hardware.
+*output* render_bit_depth 8|10
+ Controls the color channel bit depth at which frames are rendered; the
+ default is currently 8 bits per channel.
+
+ Setting higher values will not have an effect if hardware and software lack
+ support for such bit depths. Successfully increasing the render bit depth
+ will not necessarily increase the bit depth of the frames sent to a display.
+ An increased render bit depth may provide smoother rendering of gradients,
+ and screenshots which can more precisely store the colors of programs
+ which display high bit depth colors.
+
+ Warnings: this can break screenshot/screencast programs which have not been
+ updated to work with different bit depths. This command is experimental,
+ and may be removed or changed in the future.
+
# SEE ALSO
*sway*(5) *sway-input*(5)
diff --git a/sway/sway.5.scd b/sway/sway.5.scd
index e8d3d606..641d0925 100644
--- a/sway/sway.5.scd
+++ b/sway/sway.5.scd
@@ -499,6 +499,12 @@ runtime.
*client.focused_inactive*
The most recently focused view within a container which is not focused.
+ *client.focused_tab_title*
+ A view that has focused descendant container.
+ Tab or stack container title that is the parent of the focused container
+ but is not directly focused. Defaults to focused_inactive if not
+ specified and does not use the indicator and child_border colors.
+
*client.placeholder*
Ignored (present for i3 compatibility).
@@ -554,6 +560,12 @@ The default colors are:
: #ffffff
: #484e50
: #5f676a
+| *focused_tab_title*
+: #333333
+: #5f676a
+: #ffffff
+: n/a
+: n/a
| *unfocused*
: #333333
: #222222
@@ -692,9 +704,10 @@ The default colors are:
borders will only be enabled if the workspace has more than one visible
child and gaps equal to zero.
-*smart_gaps* on|off
+*smart_gaps* on|off|toggle|inverse_outer
If smart_gaps are _on_ gaps will only be enabled if a workspace has more
- than one child.
+ than one child. If smart_gaps are _inverse_outer_ outer gaps will only
+ be enabled if a workspace has exactly one child.
*mark* --add|--replace [--toggle]
Marks are arbitrary labels that can be used to identify certain windows and
diff --git a/sway/swaynag.c b/sway/swaynag.c
index ba582989..4a0a6d30 100644
--- a/sway/swaynag.c
+++ b/sway/swaynag.c
@@ -64,6 +64,8 @@ bool swaynag_spawn(const char *swaynag_command,
sway_log(SWAY_ERROR, "Failed to create fork for swaynag");
goto failed;
} else if (pid == 0) {
+ restore_nofile_limit();
+
pid = fork();
if (pid < 0) {
sway_log_errno(SWAY_ERROR, "fork failed");
diff --git a/sway/tree/container.c b/sway/tree/container.c
index 6a01eab3..79e04ec0 100644
--- a/sway/tree/container.c
+++ b/sway/tree/container.c
@@ -5,8 +5,12 @@
#include
#include
#include
+#include
#include
+#include
#include
+#include
+#include "linux-dmabuf-unstable-v1-protocol.h"
#include "cairo_util.h"
#include "pango.h"
#include "sway/config.h"
@@ -64,6 +68,7 @@ void container_destroy(struct sway_container *con) {
wlr_texture_destroy(con->title_focused_inactive);
wlr_texture_destroy(con->title_unfocused);
wlr_texture_destroy(con->title_urgent);
+ wlr_texture_destroy(con->title_focused_tab_title);
list_free(con->pending.children);
list_free(con->current.children);
list_free(con->outputs);
@@ -73,11 +78,10 @@ void container_destroy(struct sway_container *con) {
wlr_texture_destroy(con->marks_focused_inactive);
wlr_texture_destroy(con->marks_unfocused);
wlr_texture_destroy(con->marks_urgent);
+ wlr_texture_destroy(con->marks_focused_tab_title);
- if (con->view) {
- if (con->view->container == con) {
- con->view->container = NULL;
- }
+ if (con->view && con->view->container == con) {
+ con->view->container = NULL;
if (con->view->destroying) {
view_destroy(con->view);
}
@@ -382,19 +386,17 @@ struct sway_container *tiling_container_at(struct sway_node *parent,
}
static bool surface_is_popup(struct wlr_surface *surface) {
- if (wlr_surface_is_xdg_surface(surface)) {
- struct wlr_xdg_surface *xdg_surface =
- wlr_xdg_surface_from_wlr_surface(surface);
- while (xdg_surface && xdg_surface->role != WLR_XDG_SURFACE_ROLE_NONE) {
- if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) {
- return true;
- }
- xdg_surface = xdg_surface->toplevel->parent;
+ while (!wlr_surface_is_xdg_surface(surface)) {
+ if (!wlr_surface_is_subsurface(surface)) {
+ return false;
}
- return false;
+ struct wlr_subsurface *subsurface =
+ wlr_subsurface_from_wlr_surface(surface);
+ surface = subsurface->parent;
}
-
- return false;
+ struct wlr_xdg_surface *xdg_surface =
+ wlr_xdg_surface_from_wlr_surface(surface);
+ return xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP;
}
struct sway_container *container_at(struct sway_workspace *workspace,
@@ -532,6 +534,13 @@ static void render_titlebar_text_texture(struct sway_output *output,
cairo_surface_t *surface = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32, width, height);
+ cairo_status_t status = cairo_surface_status(surface);
+ if (status != CAIRO_STATUS_SUCCESS) {
+ sway_log(SWAY_ERROR, "cairo_image_surface_create failed: %s",
+ cairo_status_to_string(status));
+ return;
+ }
+
cairo_t *cairo = cairo_create(surface);
cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
cairo_set_font_options(cairo, fo);
@@ -549,8 +558,7 @@ static void render_titlebar_text_texture(struct sway_output *output,
cairo_surface_flush(surface);
unsigned char *data = cairo_image_surface_get_data(surface);
int stride = cairo_image_surface_get_stride(surface);
- struct wlr_renderer *renderer = wlr_backend_get_renderer(
- output->wlr_output->backend);
+ struct wlr_renderer *renderer = output->wlr_output->renderer;
*texture = wlr_texture_from_pixels(
renderer, DRM_FORMAT_ARGB8888, stride, width, height, data);
cairo_surface_destroy(surface);
@@ -585,6 +593,8 @@ void container_update_title_textures(struct sway_container *container) {
&config->border_colors.unfocused);
update_title_texture(container, &container->title_urgent,
&config->border_colors.urgent);
+ update_title_texture(container, &container->title_focused_tab_title,
+ &config->border_colors.focused_tab_title);
container_damage_whole(container);
}
@@ -1050,6 +1060,16 @@ void container_end_mouse_operation(struct sway_container *container) {
}
}
+static bool devid_from_fd(int fd, dev_t *devid) {
+ struct stat stat;
+ if (fstat(fd, &stat) != 0) {
+ sway_log_errno(SWAY_ERROR, "fstat failed");
+ return false;
+ }
+ *devid = stat.st_rdev;
+ return true;
+}
+
static void set_fullscreen(struct sway_container *con, bool enable) {
if (!con->view) {
return;
@@ -1061,6 +1081,75 @@ static void set_fullscreen(struct sway_container *con, bool enable) {
con->view->foreign_toplevel, enable);
}
}
+
+ if (!server.linux_dmabuf_v1 || !con->view->surface) {
+ return;
+ }
+ if (!enable) {
+ wlr_linux_dmabuf_v1_set_surface_feedback(server.linux_dmabuf_v1,
+ con->view->surface, NULL);
+ return;
+ }
+
+ if (!con->pending.workspace || !con->pending.workspace->output) {
+ return;
+ }
+
+ struct sway_output *output = con->pending.workspace->output;
+ struct wlr_output *wlr_output = output->wlr_output;
+
+ // TODO: add wlroots helpers for all of this stuff
+
+ const struct wlr_drm_format_set *renderer_formats =
+ wlr_renderer_get_dmabuf_texture_formats(server.renderer);
+ assert(renderer_formats);
+
+ int renderer_drm_fd = wlr_renderer_get_drm_fd(server.renderer);
+ int backend_drm_fd = wlr_backend_get_drm_fd(wlr_output->backend);
+ if (renderer_drm_fd < 0 || backend_drm_fd < 0) {
+ return;
+ }
+
+ dev_t render_dev, scanout_dev;
+ if (!devid_from_fd(renderer_drm_fd, &render_dev) ||
+ !devid_from_fd(backend_drm_fd, &scanout_dev)) {
+ return;
+ }
+
+ const struct wlr_drm_format_set *output_formats =
+ wlr_output_get_primary_formats(output->wlr_output,
+ WLR_BUFFER_CAP_DMABUF);
+ if (!output_formats) {
+ return;
+ }
+
+ struct wlr_drm_format_set scanout_formats = {0};
+ if (!wlr_drm_format_set_intersect(&scanout_formats,
+ output_formats, renderer_formats)) {
+ return;
+ }
+
+ struct wlr_linux_dmabuf_feedback_v1_tranche tranches[] = {
+ {
+ .target_device = scanout_dev,
+ .flags = ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT,
+ .formats = &scanout_formats,
+ },
+ {
+ .target_device = render_dev,
+ .formats = renderer_formats,
+ },
+ };
+
+ const struct wlr_linux_dmabuf_feedback_v1 feedback = {
+ .main_device = render_dev,
+ .tranches = tranches,
+ .tranches_len = sizeof(tranches) / sizeof(tranches[0]),
+ };
+ wlr_linux_dmabuf_v1_set_surface_feedback(server.linux_dmabuf_v1,
+ con->view->surface, &feedback);
+
+ wlr_drm_format_set_finish(&scanout_formats);
}
static void container_fullscreen_workspace(struct sway_container *con) {
@@ -1638,6 +1727,8 @@ void container_update_marks_textures(struct sway_container *con) {
&config->border_colors.unfocused);
update_marks_texture(con, &con->marks_urgent,
&config->border_colors.urgent);
+ update_marks_texture(con, &con->marks_focused_tab_title,
+ &config->border_colors.focused_tab_title);
container_damage_whole(con);
}
diff --git a/sway/tree/output.c b/sway/tree/output.c
index c095dce0..ad8d2482 100644
--- a/sway/tree/output.c
+++ b/sway/tree/output.c
@@ -56,8 +56,8 @@ static void restore_workspaces(struct sway_output *output) {
}
// Saved workspaces
- while (root->noop_output->workspaces->length) {
- struct sway_workspace *ws = root->noop_output->workspaces->items[0];
+ while (root->fallback_output->workspaces->length) {
+ struct sway_workspace *ws = root->fallback_output->workspaces->items[0];
workspace_detach(ws);
output_add_workspace(output, ws);
@@ -95,7 +95,7 @@ struct sway_output *output_create(struct wlr_output *wlr_output) {
output->detected_subpixel = wlr_output->subpixel;
output->scale_filter = SCALE_FILTER_NEAREST;
- wl_signal_init(&output->events.destroy);
+ wl_signal_init(&output->events.disable);
wl_list_insert(&root->all_outputs, &output->link);
@@ -192,7 +192,7 @@ static void output_evacuate(struct sway_output *output) {
new_output = fallback_output;
}
if (!new_output) {
- new_output = root->noop_output;
+ new_output = root->fallback_output;
}
struct sway_workspace *new_output_ws =
@@ -262,7 +262,7 @@ void output_disable(struct sway_output *output) {
}
sway_log(SWAY_DEBUG, "Disabling output '%s'", output->wlr_output->name);
- wl_signal_emit(&output->events.destroy, output);
+ wl_signal_emit(&output->events.disable, output);
output_evacuate(output);
@@ -286,13 +286,10 @@ void output_begin_destroy(struct sway_output *output) {
return;
}
sway_log(SWAY_DEBUG, "Destroying output '%s'", output->wlr_output->name);
+ wl_signal_emit(&output->node.events.destroy, &output->node);
output->node.destroying = true;
node_set_dirty(&output->node);
-
- wl_list_remove(&output->link);
- output->wlr_output->data = NULL;
- output->wlr_output = NULL;
}
struct sway_output *output_from_wlr_output(struct wlr_output *output) {
diff --git a/sway/tree/root.c b/sway/tree/root.c
index dd4d8e33..73f3993c 100644
--- a/sway/tree/root.c
+++ b/sway/tree/root.c
@@ -374,8 +374,8 @@ void root_for_each_container(void (*f)(struct sway_container *con, void *data),
}
// Saved workspaces
- for (int i = 0; i < root->noop_output->workspaces->length; ++i) {
- struct sway_workspace *ws = root->noop_output->workspaces->items[i];
+ for (int i = 0; i < root->fallback_output->workspaces->length; ++i) {
+ struct sway_workspace *ws = root->fallback_output->workspaces->items[i];
workspace_for_each_container(ws, f, data);
}
}
@@ -427,8 +427,8 @@ struct sway_container *root_find_container(
}
// Saved workspaces
- for (int i = 0; i < root->noop_output->workspaces->length; ++i) {
- struct sway_workspace *ws = root->noop_output->workspaces->items[i];
+ for (int i = 0; i < root->fallback_output->workspaces->length; ++i) {
+ struct sway_workspace *ws = root->fallback_output->workspaces->items[i];
if ((result = workspace_find_container(ws, test, data))) {
return result;
}
diff --git a/sway/tree/view.c b/sway/tree/view.c
index ed8c50f8..8b7061ba 100644
--- a/sway/tree/view.c
+++ b/sway/tree/view.c
@@ -752,10 +752,29 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
}
struct sway_seat *seat = input_manager_current_seat();
- struct sway_node *node = ws ? seat_get_focus_inactive(seat, &ws->node)
- : seat_get_focus_inactive(seat, &root->node);
- struct sway_container *target_sibling = node->type == N_CONTAINER ?
- node->sway_container : NULL;
+ struct sway_node *node =
+ seat_get_focus_inactive(seat, ws ? &ws->node : &root->node);
+ struct sway_container *target_sibling = NULL;
+ if (node && node->type == N_CONTAINER) {
+ if (container_is_floating(node->sway_container)) {
+ // If we're about to launch the view into the floating container, then
+ // launch it as a tiled view instead.
+ if (ws) {
+ target_sibling = seat_get_focus_inactive_tiling(seat, ws);
+ if (target_sibling) {
+ struct sway_container *con =
+ seat_get_focus_inactive_view(seat, &target_sibling->node);
+ if (con) {
+ target_sibling = con;
+ }
+ }
+ } else {
+ ws = seat_get_last_known_workspace(seat);
+ }
+ } else {
+ target_sibling = node->sway_container;
+ }
+ }
view->foreign_toplevel =
wlr_foreign_toplevel_handle_v1_create(server.foreign_toplevel_manager);
@@ -776,13 +795,6 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
&view->foreign_minimize);
- // If we're about to launch the view into the floating container, then
- // launch it as a tiled view in the root of the workspace instead.
- if (target_sibling && container_is_floating(target_sibling)) {
- target_sibling = NULL;
- ws = seat_get_last_known_workspace(seat);
- }
-
struct sway_container *container = view->container;
if (target_sibling) {
container_add_sibling(target_sibling, container, 1);
@@ -1129,9 +1141,12 @@ void view_child_init(struct sway_view_child *child,
wl_signal_add(&view->events.unmap, &child->view_unmap);
child->view_unmap.notify = view_child_handle_view_unmap;
- struct sway_workspace *workspace = child->view->container->pending.workspace;
- if (workspace) {
- wlr_surface_send_enter(child->surface, workspace->output->wlr_output);
+ struct sway_container *container = child->view->container;
+ if (container != NULL) {
+ struct sway_workspace *workspace = container->pending.workspace;
+ if (workspace) {
+ wlr_surface_send_enter(child->surface, workspace->output->wlr_output);
+ }
}
view_child_init_subsurfaces(child, surface);
diff --git a/sway/tree/workspace.c b/sway/tree/workspace.c
index 8dd7789d..c84320bd 100644
--- a/sway/tree/workspace.c
+++ b/sway/tree/workspace.c
@@ -50,8 +50,8 @@ struct sway_output *workspace_get_initial_output(const char *name) {
} else if (focus && focus->type == N_CONTAINER) {
return focus->sway_container->pending.workspace->output;
}
- // Fallback to the first output or noop output for headless
- return root->outputs->length ? root->outputs->items[0] : root->noop_output;
+ // Fallback to the first output or the headless output
+ return root->outputs->length ? root->outputs->items[0] : root->fallback_output;
}
struct sway_workspace *workspace_create(struct sway_output *output,
@@ -844,24 +844,36 @@ struct sway_container *workspace_insert_tiling(struct sway_workspace *workspace,
return con;
}
+bool workspace_has_single_visible_container(struct sway_workspace *ws) {
+ struct sway_seat *seat = input_manager_get_default_seat();
+ struct sway_container *focus =
+ seat_get_focus_inactive_tiling(seat, ws);
+ if (focus && !focus->view) {
+ focus = seat_get_focus_inactive_view(seat, &focus->node);
+ }
+ return (focus && focus->view && view_ancestor_is_only_visible(focus->view));
+}
+
void workspace_add_gaps(struct sway_workspace *ws) {
- if (config->smart_gaps) {
- struct sway_seat *seat = input_manager_get_default_seat();
- struct sway_container *focus =
- seat_get_focus_inactive_tiling(seat, ws);
- if (focus && !focus->view) {
- focus = seat_get_focus_inactive_view(seat, &focus->node);
- }
- if (focus && focus->view && view_ancestor_is_only_visible(focus->view)) {
- ws->current_gaps.top = 0;
- ws->current_gaps.right = 0;
- ws->current_gaps.bottom = 0;
- ws->current_gaps.left = 0;
- return;
- }
+ if (config->smart_gaps == SMART_GAPS_ON
+ && workspace_has_single_visible_container(ws)) {
+ ws->current_gaps.top = 0;
+ ws->current_gaps.right = 0;
+ ws->current_gaps.bottom = 0;
+ ws->current_gaps.left = 0;
+ return;
+ }
+
+ if (config->smart_gaps == SMART_GAPS_INVERSE_OUTER
+ && !workspace_has_single_visible_container(ws)) {
+ ws->current_gaps.top = 0;
+ ws->current_gaps.right = 0;
+ ws->current_gaps.bottom = 0;
+ ws->current_gaps.left = 0;
+ } else {
+ ws->current_gaps = ws->gaps_outer;
}
- ws->current_gaps = ws->gaps_outer;
// Add inner gaps and make sure we don't turn out negative
ws->current_gaps.top = fmax(0, ws->current_gaps.top + ws->gaps_inner);
ws->current_gaps.right = fmax(0, ws->current_gaps.right + ws->gaps_inner);
diff --git a/swaybar/bar.c b/swaybar/bar.c
index 15eab782..6ffdc9b4 100644
--- a/swaybar/bar.c
+++ b/swaybar/bar.c
@@ -54,7 +54,6 @@ static void swaybar_output_free(struct swaybar_output *output) {
if (output->input_region != NULL) {
wl_region_destroy(output->input_region);
}
- zxdg_output_v1_destroy(output->xdg_output);
wl_output_destroy(output->output);
destroy_buffer(&output->buffers[0]);
destroy_buffer(&output->buffers[1]);
@@ -172,7 +171,7 @@ bool determine_bar_visibility(struct swaybar *bar, bool moving_layer) {
if (bar->status) {
sway_log(SWAY_DEBUG, "Sending %s signal to status command",
visible ? "cont" : "stop");
- kill(bar->status->pid, visible ?
+ kill(-bar->status->pid, visible ?
bar->status->cont_signal : bar->status->stop_signal);
}
}
diff --git a/swaybar/ipc.c b/swaybar/ipc.c
index a64aa1ab..2cb235bf 100644
--- a/swaybar/ipc.c
+++ b/swaybar/ipc.c
@@ -550,7 +550,7 @@ bool handle_ipc_readable(struct swaybar *bar) {
// The default depth of 32 is too small to represent some nested layouts, but
// we can't pass INT_MAX here because json-c (as of this writing) prefaults
// all the memory for its stack.
- json_tokener *tok = json_tokener_new_ex(256);
+ json_tokener *tok = json_tokener_new_ex(JSON_MAX_DEPTH);
if (!tok) {
sway_log_errno(SWAY_ERROR, "failed to create tokener");
free_ipc_response(resp);
diff --git a/swaybar/status_line.c b/swaybar/status_line.c
index ecd91032..2e9bb7f1 100644
--- a/swaybar/status_line.c
+++ b/swaybar/status_line.c
@@ -117,11 +117,11 @@ bool status_handle_readable(struct status_line *status) {
status->text = status->buffer;
// intentional fall-through
case PROTOCOL_TEXT:
- errno = 0;
while (true) {
if (status->buffer[read_bytes - 1] == '\n') {
status->buffer[read_bytes - 1] = '\0';
}
+ errno = 0;
read_bytes = getline(&status->buffer,
&status->buffer_size, status->read);
if (errno == EAGAIN) {
@@ -157,7 +157,12 @@ struct status_line *status_line_init(char *cmd) {
assert(!getenv("WAYLAND_SOCKET") && "display must be initialized before "
" starting `status-command`; WAYLAND_SOCKET should not be set");
status->pid = fork();
- if (status->pid == 0) {
+ if (status->pid < 0) {
+ sway_log_errno(SWAY_ERROR, "fork failed");
+ exit(1);
+ } else if (status->pid == 0) {
+ setpgid(0, 0);
+
dup2(pipe_read_fd[1], STDOUT_FILENO);
close(pipe_read_fd[0]);
close(pipe_read_fd[1]);
@@ -185,8 +190,8 @@ struct status_line *status_line_init(char *cmd) {
void status_line_free(struct status_line *status) {
status_line_close_fds(status);
- kill(status->pid, status->cont_signal);
- kill(status->pid, SIGTERM);
+ kill(-status->pid, status->cont_signal);
+ kill(-status->pid, SIGTERM);
waitpid(status->pid, NULL, 0);
if (status->protocol == PROTOCOL_I3BAR) {
struct i3bar_block *block, *tmp;
diff --git a/swaybar/tray/item.c b/swaybar/tray/item.c
index 19f4beac..6d4b17bf 100644
--- a/swaybar/tray/item.c
+++ b/swaybar/tray/item.c
@@ -493,24 +493,36 @@ uint32_t render_sni(cairo_t *cairo, struct swaybar_output *output, double *x,
cairo_destroy(cairo_icon);
}
- int padded_size = icon_size + 2*padding;
- *x -= padded_size;
- int y = floor((height - padded_size) / 2.0);
+ double descaled_padding = (double)padding / output->scale;
+ double descaled_icon_size = (double)icon_size / output->scale;
+
+ int size = descaled_icon_size + 2 * descaled_padding;
+ *x -= size;
+ int icon_y = floor((output->height - size) / 2.0);
cairo_operator_t op = cairo_get_operator(cairo);
cairo_set_operator(cairo, CAIRO_OPERATOR_OVER);
- cairo_set_source_surface(cairo, icon, *x + padding, y + padding);
- cairo_rectangle(cairo, *x, y, padded_size, padded_size);
+
+ cairo_matrix_t scale_matrix;
+ cairo_pattern_t *icon_pattern = cairo_pattern_create_for_surface(icon);
+ // TODO: check cairo_pattern_status for "ENOMEM"
+ cairo_matrix_init_scale(&scale_matrix, output->scale, output->scale);
+ cairo_matrix_translate(&scale_matrix, -(*x + descaled_padding), -(icon_y + descaled_padding));
+ cairo_pattern_set_matrix(icon_pattern, &scale_matrix);
+ cairo_set_source(cairo, icon_pattern);
+ cairo_rectangle(cairo, *x, icon_y, size, size);
cairo_fill(cairo);
+
cairo_set_operator(cairo, op);
+ cairo_pattern_destroy(icon_pattern);
cairo_surface_destroy(icon);
struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot));
hotspot->x = *x;
hotspot->y = 0;
- hotspot->width = height;
- hotspot->height = height;
+ hotspot->width = size;
+ hotspot->height = output->height;
hotspot->callback = icon_hotspot_callback;
hotspot->destroy = free;
hotspot->data = strdup(sni->watcher_id);
diff --git a/swaybar/tray/tray.c b/swaybar/tray/tray.c
index 5fe6f9c3..b0545f4a 100644
--- a/swaybar/tray/tray.c
+++ b/swaybar/tray/tray.c
@@ -116,8 +116,8 @@ uint32_t render_tray(cairo_t *cairo, struct swaybar_output *output, double *x) {
}
} // else display on all
- if ((int) output->height*output->scale <= 2*config->tray_padding) {
- return 2*config->tray_padding + 1;
+ if ((int)(output->height * output->scale) <= 2 * config->tray_padding) {
+ return (2 * config->tray_padding + 1) / output->scale;
}
uint32_t max_height = 0;
diff --git a/swaymsg/main.c b/swaymsg/main.c
index 574d3b75..0d9dc5a0 100644
--- a/swaymsg/main.c
+++ b/swaymsg/main.c
@@ -1,4 +1,6 @@
#define _POSIX_C_SOURCE 200809L
+
+#include
#include
#include
#include
@@ -480,12 +482,20 @@ int main(int argc, char **argv) {
char *resp = ipc_single_command(socketfd, type, command, &len);
// pretty print the json
- json_object *obj = json_tokener_parse(resp);
- if (obj == NULL) {
+ json_tokener *tok = json_tokener_new_ex(JSON_MAX_DEPTH);
+ if (tok == NULL) {
+ if (quiet) {
+ exit(EXIT_FAILURE);
+ }
+ sway_abort("failed allocating json_tokener");
+ }
+ json_object *obj = json_tokener_parse_ex(tok, resp, -1);
+ enum json_tokener_error err = json_tokener_get_error(tok);
+ json_tokener_free(tok);
+ if (obj == NULL || err != json_tokener_success) {
if (!quiet) {
- fprintf(stderr, "ERROR: Could not parse json response from ipc. "
- "This is a bug in sway.");
- printf("%s\n", resp);
+ sway_log(SWAY_ERROR, "failed to parse payload as json: %s",
+ json_tokener_error_desc(err));
}
ret = 1;
} else {
@@ -517,13 +527,22 @@ int main(int argc, char **argv) {
break;
}
- json_object *obj = json_tokener_parse(reply->payload);
- if (obj == NULL) {
- if (!quiet) {
- fprintf(stderr, "ERROR: Could not parse json response from"
- " ipc. This is a bug in sway.");
- ret = 1;
+ json_tokener *tok = json_tokener_new_ex(JSON_MAX_DEPTH);
+ if (tok == NULL) {
+ if (quiet) {
+ exit(EXIT_FAILURE);
}
+ sway_abort("failed allocating json_tokener");
+ }
+ json_object *obj = json_tokener_parse_ex(tok, reply->payload, -1);
+ enum json_tokener_error err = json_tokener_get_error(tok);
+ json_tokener_free(tok);
+ if (obj == NULL || err != json_tokener_success) {
+ if (!quiet) {
+ sway_log(SWAY_ERROR, "failed to parse payload as json: %s",
+ json_tokener_error_desc(err));
+ }
+ ret = 1;
break;
} else if (quiet) {
json_object_put(obj);
diff --git a/swaynag/swaynag.c b/swaynag/swaynag.c
index 6d4a7a58..9b57d578 100644
--- a/swaynag/swaynag.c
+++ b/swaynag/swaynag.c
@@ -307,33 +307,25 @@ static void output_scale(void *data, struct wl_output *output,
}
}
+static void output_name(void *data, struct wl_output *output,
+ const char *name) {
+ struct swaynag_output *swaynag_output = data;
+ swaynag_output->name = strdup(name);
+
+ const char *outname = swaynag_output->swaynag->type->output;
+ if (!swaynag_output->swaynag->output && outname &&
+ strcmp(outname, name) == 0) {
+ sway_log(SWAY_DEBUG, "Using output %s", name);
+ swaynag_output->swaynag->output = swaynag_output;
+ }
+}
+
static const struct wl_output_listener output_listener = {
.geometry = nop,
.mode = nop,
.done = nop,
.scale = output_scale,
-};
-
-static void xdg_output_handle_name(void *data,
- struct zxdg_output_v1 *xdg_output, const char *name) {
- struct swaynag_output *swaynag_output = data;
- char *outname = swaynag_output->swaynag->type->output;
- sway_log(SWAY_DEBUG, "Checking against output %s for %s", name, outname);
- if (!swaynag_output->swaynag->output && outname && name
- && strcmp(outname, name) == 0) {
- sway_log(SWAY_DEBUG, "Using output %s", name);
- swaynag_output->swaynag->output = swaynag_output;
- }
- swaynag_output->name = strdup(name);
- zxdg_output_v1_destroy(xdg_output);
- swaynag_output->swaynag->querying_outputs--;
-}
-
-static const struct zxdg_output_v1_listener xdg_output_listener = {
- .logical_position = nop,
- .logical_size = nop,
- .done = nop,
- .name = xdg_output_handle_name,
+ .name = output_name,
.description = nop,
};
@@ -361,33 +353,21 @@ static void handle_global(void *data, struct wl_registry *registry,
} else if (strcmp(interface, wl_shm_interface.name) == 0) {
swaynag->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
} else if (strcmp(interface, wl_output_interface.name) == 0) {
- if (!swaynag->output && swaynag->xdg_output_manager) {
- swaynag->querying_outputs++;
+ if (!swaynag->output) {
struct swaynag_output *output =
calloc(1, sizeof(struct swaynag_output));
output->wl_output = wl_registry_bind(registry, name,
- &wl_output_interface, 3);
+ &wl_output_interface, 4);
output->wl_name = name;
output->scale = 1;
output->swaynag = swaynag;
wl_list_insert(&swaynag->outputs, &output->link);
wl_output_add_listener(output->wl_output,
&output_listener, output);
-
- struct zxdg_output_v1 *xdg_output;
- xdg_output = zxdg_output_manager_v1_get_xdg_output(
- swaynag->xdg_output_manager, output->wl_output);
- zxdg_output_v1_add_listener(xdg_output,
- &xdg_output_listener, output);
}
} else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
swaynag->layer_shell = wl_registry_bind(
registry, name, &zwlr_layer_shell_v1_interface, 1);
- } else if (strcmp(interface, zxdg_output_manager_v1_interface.name) == 0
- && version >= ZXDG_OUTPUT_V1_NAME_SINCE_VERSION) {
- swaynag->xdg_output_manager = wl_registry_bind(registry, name,
- &zxdg_output_manager_v1_interface,
- ZXDG_OUTPUT_V1_NAME_SINCE_VERSION);
}
}
@@ -453,12 +433,11 @@ void swaynag_setup(struct swaynag *swaynag) {
assert(swaynag->compositor && swaynag->layer_shell && swaynag->shm);
- while (swaynag->querying_outputs > 0) {
- if (wl_display_roundtrip(swaynag->display) < 0) {
- sway_log(SWAY_ERROR, "Error during outputs init.");
- swaynag_destroy(swaynag);
- exit(EXIT_FAILURE);
- }
+ // Second roundtrip to get wl_output properties
+ if (wl_display_roundtrip(swaynag->display) < 0) {
+ sway_log(SWAY_ERROR, "Error during outputs init.");
+ swaynag_destroy(swaynag);
+ exit(EXIT_FAILURE);
}
if (!swaynag->output && swaynag->type->output) {