Merge pull request #1 from swaywm/v1.7

V1.7
This commit is contained in:
William McKinnon 2022-04-26 21:44:51 -04:00 committed by GitHub
commit 4660771f6a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
77 changed files with 703 additions and 306 deletions

View file

@ -21,7 +21,7 @@ packages:
- xwayland - xwayland
sources: sources:
- https://github.com/swaywm/sway - https://github.com/swaywm/sway
- https://github.com/swaywm/wlroots - https://gitlab.freedesktop.org/wlroots/wlroots.git#0.15.0
tasks: tasks:
- wlroots: | - wlroots: |
cd wlroots cd wlroots

View file

@ -18,7 +18,7 @@ packages:
- seatd - seatd
sources: sources:
- https://github.com/swaywm/sway - https://github.com/swaywm/sway
- https://github.com/swaywm/wlroots - https://gitlab.freedesktop.org/wlroots/wlroots.git#0.15.0
tasks: tasks:
- wlroots: | - wlroots: |
cd wlroots cd wlroots

View file

@ -26,7 +26,7 @@ packages:
- x11/xcb-util-wm - x11/xcb-util-wm
sources: sources:
- https://github.com/swaywm/sway - https://github.com/swaywm/sway
- https://github.com/swaywm/wlroots - https://gitlab.freedesktop.org/wlroots/wlroots.git#0.15.0
tasks: tasks:
- setup: | - setup: |
cd sway cd sway

View file

@ -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

View file

@ -15,7 +15,7 @@ Falls du sway für deine eigene Distribution als Paket bereitstellen möchtest,
sway benötigt die folgenden Pakete: sway benötigt die folgenden Pakete:
* meson\* * meson\*
* [wlroots](https://github.com/swaywm/wlroots) * [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland * wayland
* wayland-protocols\* * wayland-protocols\*
* pcre * pcre

View file

@ -70,5 +70,5 @@ support til dem (gdm er kendt for at fungere temmelig godt).
[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48 [E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
[GitHub releases]: https://github.com/swaywm/sway/releases [GitHub releases]: https://github.com/swaywm/sway/releases
[Opsætning til udvikling]: https://github.com/swaywm/sway/wiki/Development-Setup [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 [scdoc]: https://git.sr.ht/~sircmpwn/scdoc

View file

@ -25,7 +25,7 @@ escriba un email a sir@cmpwn.com
Instale las dependencias: Instale las dependencias:
* meson \* * meson \*
* [wlroots](https://github.com/swaywm/wlroots) * [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland * wayland
* wayland-protocols \* * wayland-protocols \*
* pcre * pcre

View file

@ -79,5 +79,5 @@ bien fonctionner).
[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48 [E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
[versions GitHub]: https://github.com/swaywm/sway/releases [versions GitHub]: https://github.com/swaywm/sway/releases
[Configuration de développement]: https://github.com/swaywm/sway/wiki/Development-Setup [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 [scdoc]: https://git.sr.ht/~sircmpwn/scdoc

View file

@ -69,5 +69,5 @@ _\*Compile-time dep_
[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48 [E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
[GitHub releases]: https://github.com/swaywm/sway/releases [GitHub releases]: https://github.com/swaywm/sway/releases
[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup [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 [scdoc]: https://git.sr.ht/~sircmpwn/scdoc

View file

@ -73,5 +73,5 @@ gdm-ről ismeretes, hogy egész jól működik.)
[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48 [E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
[GitHub releases]: https://github.com/swaywm/sway/releases [GitHub releases]: https://github.com/swaywm/sway/releases
[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup [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 [scdoc]: https://git.sr.ht/~sircmpwn/scdoc

View file

@ -1,9 +1,7 @@
<div dir="rtl">
# sway # sway
sway یک کامپوزیتور الهام گرفته از [i3](https://i3wm.org/) بر روی [Wayland](http://wayland.freedesktop.org/) است. [سوال‌های متداول](https://github.com/swaywm/sway/wiki) را بخوانید. در [کانال &rlm;sway یک کامپوزیتور الهام گرفته از [i3](https://i3wm.org/) بر روی [Wayland](http://wayland.freedesktop.org/) است. [سوال‌های متداول](https://github.com/swaywm/sway/wiki) را بخوانید. در [کانال
IRC](http://web.libera.chat/gamja/?channels=sway&uio=d4) عضو شوید (#sway sur IRC](http://web.libera.chat/gamja/?channels=sway&uio=d4) عضو شوید (&lrm;#sway&rlm; در
irc.libera.chat). irc.libera.chat).
برای حمایت از تیم توسعه sway به [صفحه برای حمایت از تیم توسعه sway به [صفحه
@ -17,7 +15,7 @@ Patreon با نام کاربری SirCmpwn](https://patreon.com/sircmpwn) مرا
### از بسته‌های رسمی ### از بسته‌های رسمی
sway در بسته‌های رسمی توزیع‌های مختلف وجود دارد. بسته «sway» را نصب کنید. در صورتی که بسته رسمی وجود نداشت، برای آگاهی بیشتر درباره نصب روی توزیعتان به این [صفحه راهنما](https://github.com/swaywm/sway/wiki/Unsupported-packages) مراجعه کنید. &rlm;sway در بسته‌های رسمی توزیع‌های مختلف وجود دارد. بسته «sway» را نصب کنید. در صورتی که بسته رسمی وجود نداشت، برای آگاهی بیشتر درباره نصب روی توزیعتان به این [صفحه راهنما](https://github.com/swaywm/sway/wiki/Unsupported-packages) مراجعه کنید.
اگر به ایجاد بسته sway برای توزیعتان علاقه‌مند هستید، از کانال IRC استفاده کنید یا به sir@cmpwn.com ایمیل بزنید. اگر به ایجاد بسته sway برای توزیعتان علاقه‌مند هستید، از کانال IRC استفاده کنید یا به sir@cmpwn.com ایمیل بزنید.
@ -28,7 +26,7 @@ sway در بسته‌های رسمی توزیع‌های مختلف وجود د
بسته‌های مورد نیاز: بسته‌های مورد نیاز:
* meson \* * meson \*
* [wlroots](https://github.com/swaywm/wlroots) * [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland * wayland
* wayland-protocols \* * wayland-protocols \*
* pcre * pcre
@ -42,21 +40,16 @@ sway در بسته‌های رسمی توزیع‌های مختلف وجود د
_\*نیازمندی‌های زمان کامپایل برنامه_ _\*نیازمندی‌های زمان کامپایل برنامه_
این فرمان‌ها را اجرا کنید: این فرمان‌ها را اجرا کنید:
</div>
meson build meson build
ninja -C build ninja -C build
sudo ninja -C build install sudo ninja -C build install
<div dir="rtl">
روی سیستم‌های بدون logind، باید فرمان زیر را برای suid کردن باینری sway اجرا کنید: روی سیستم‌های بدون logind، باید فرمان زیر را برای suid کردن باینری sway اجرا کنید:
</div>
sudo chmod a+s /usr/local/bin/sway sudo chmod a+s /usr/local/bin/sway
<div dir="rtl"> &rlm;sway پس از startup مجوزهای دسترسی root را رها می‌کند.
sway پس از startup مجوزهای دسترسی root را رها می‌کند.
### شخصی سازی و تنظیمات ### شخصی سازی و تنظیمات
@ -64,7 +57,4 @@ sway پس از startup مجوزهای دسترسی root را رها می‌کن
## اجرا ## اجرا
در محیط TTY کافیست `sway` را اجرا کنید. ممکن است ابزارهای مدیریت نمایشگری نیز برای این کار وجود داشته باشند اما از طرف sway پشتیبانی نمی‌شوند (gdm عملکرد خوبی در این زمینه دارد). در محیط TTY کافیست `sway` را اجرا کنید. ممکن است ابزارهای مدیریت نمایشگری نیز برای این کار وجود داشته باشند اما از طرف sway پشتیبانی نمی‌شوند (gdm عملکرد خوبی در این زمینه دارد).
</div>

View file

@ -27,7 +27,7 @@ Swayは沢山のディストリビューションで提供されています。"
次の依存パッケージをインストールしてください: 次の依存パッケージをインストールしてください:
* meson \* * meson \*
* [wlroots](https://github.com/swaywm/wlroots) * [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland * wayland
* wayland-protocols \* * wayland-protocols \*
* pcre * pcre

View file

@ -24,7 +24,7 @@ IRC 채널을 방문하거나 sir@cmpwn.com으로 이메일을 보내 상담 받
다음 의존 패키지들을 설치해 주세요: 다음 의존 패키지들을 설치해 주세요:
* meson \* * meson \*
* [wlroots](https://github.com/swaywm/wlroots) * [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland * wayland
* wayland-protocols \* * wayland-protocols \*
* pcre * pcre

View file

@ -87,5 +87,5 @@ sway (gdm is known to work fairly well).
[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48 [E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
[GitHub releases]: https://github.com/swaywm/sway/releases [GitHub releases]: https://github.com/swaywm/sway/releases
[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup [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 [scdoc]: https://git.sr.ht/~sircmpwn/scdoc

View file

@ -25,7 +25,7 @@ kanaal of stuur een e-mail naar sir@cmpwn.com voor advies.
Afhankelijkheden installeren: Afhankelijkheden installeren:
* meson \* * meson \*
* [wlroots](https://github.com/swaywm/wlroots) * [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland * wayland
* wayland-protocols \* * wayland-protocols \*
* pcre * pcre

View file

@ -25,7 +25,7 @@ adres sir@cmpwn.com w celu uzyskania wskazówek.
Zainstaluj zależności: Zainstaluj zależności:
* meson \* * meson \*
* [wlroots](https://github.com/swaywm/wlroots) * [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland * wayland
* wayland-protocols \* * wayland-protocols \*
* pcre * pcre

View file

@ -27,7 +27,7 @@ Verifique [essa página da wiki](https://github.com/swaywm/sway/wiki/Development
Instale as dependências: Instale as dependências:
* meson \* * meson \*
* [wlroots](https://github.com/swaywm/wlroots) * [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland * wayland
* wayland-protocols \* * wayland-protocols \*
* pcre * pcre

View file

@ -22,7 +22,7 @@ Dacă sunteți interesați in a crea pachete pentru distribuția voastră, infor
Dependențe pentru instalare: Dependențe pentru instalare:
* meson \* * meson \*
* [wlroots](https://github.com/swaywm/wlroots) * [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland * wayland
* wayland-protocols \* * wayland-protocols \*
* pcre * pcre

View file

@ -70,5 +70,5 @@ sway (gdm работает довольно неплохо).
[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48 [E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
[GitHub releases]: https://github.com/swaywm/sway/releases [GitHub releases]: https://github.com/swaywm/sway/releases
[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup [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 [scdoc]: https://git.sr.ht/~sircmpwn/scdoc

View file

@ -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 [E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
[GitHub releases]: https://github.com/swaywm/sway/releases [GitHub releases]: https://github.com/swaywm/sway/releases
[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup [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 [scdoc]: https://git.sr.ht/~sircmpwn/scdoc

View file

@ -36,7 +36,7 @@ Sway доступний у багатьох дистрибутивах Linux (а
Встановіть залежності: Встановіть залежності:
* meson \* * meson \*
* [wlroots](https://github.com/swaywm/wlroots) * [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland * wayland
* wayland-protocols \* * wayland-protocols \*
* pcre * pcre

View file

@ -25,7 +25,7 @@ Sway 在很多发行版中可用. 尝试在你的发行版中安装 "sway" 包.
安装依赖: 安装依赖:
* meson \* * meson \*
* [wlroots](https://github.com/swaywm/wlroots) * [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland * wayland
* wayland-protocols \* * wayland-protocols \*
* pcre * pcre

View file

@ -25,7 +25,7 @@ Sway 在許多發行版都有提供。請自己嘗試於你的發行版安裝
相依套件: 相依套件:
* meson \* * meson \*
* [wlroots](https://github.com/swaywm/wlroots) * [wlroots](https://gitlab.freedesktop.org/wlroots/wlroots)
* wayland * wayland
* wayland-protocols \* * wayland-protocols \*
* pcre * pcre

View file

@ -80,6 +80,12 @@ enum movement_unit parse_movement_unit(const char *unit) {
int parse_movement_amount(int argc, char **argv, int parse_movement_amount(int argc, char **argv,
struct movement_amount *amount) { 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; char *err;
amount->amount = (int)strtol(argv[0], &err, 10); amount->amount = (int)strtol(argv[0], &err, 10);
if (*err) { if (*err) {

View file

@ -1,6 +1,9 @@
#ifndef _SWAY_IPC_CLIENT_H #ifndef _SWAY_IPC_CLIENT_H
#define _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 <stdbool.h> #include <stdbool.h>
#include <stdint.h> #include <stdint.h>
#include <sys/time.h> #include <sys/time.h>

View file

@ -112,6 +112,7 @@ sway_cmd cmd_border;
sway_cmd cmd_client_noop; sway_cmd cmd_client_noop;
sway_cmd cmd_client_focused; sway_cmd cmd_client_focused;
sway_cmd cmd_client_focused_inactive; sway_cmd cmd_client_focused_inactive;
sway_cmd cmd_client_focused_tab_title;
sway_cmd cmd_client_unfocused; sway_cmd cmd_client_unfocused;
sway_cmd cmd_client_urgent; sway_cmd cmd_client_urgent;
sway_cmd cmd_client_placeholder; 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_mode;
sway_cmd output_cmd_modeline; sway_cmd output_cmd_modeline;
sway_cmd output_cmd_position; sway_cmd output_cmd_position;
sway_cmd output_cmd_render_bit_depth;
sway_cmd output_cmd_scale; sway_cmd output_cmd_scale;
sway_cmd output_cmd_scale_filter; sway_cmd output_cmd_scale_filter;
sway_cmd output_cmd_subpixel; sway_cmd output_cmd_subpixel;

View file

@ -247,6 +247,12 @@ enum scale_filter_mode {
SCALE_FILTER_SMART, 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. * Size and position configuration for a particular output.
* *
@ -266,6 +272,7 @@ struct output_config {
enum wl_output_subpixel subpixel; enum wl_output_subpixel subpixel;
int max_render_time; // In milliseconds int max_render_time; // In milliseconds
int adaptive_sync; int adaptive_sync;
enum render_bit_depth render_bit_depth;
char *background; char *background;
char *background_option; char *background_option;
@ -283,6 +290,12 @@ struct side_gaps {
int left; 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 * Stores configuration for a workspace, regardless of whether the workspace
* exists. * exists.
@ -512,7 +525,7 @@ struct sway_config {
bool tiling_drag; bool tiling_drag;
int tiling_drag_threshold; int tiling_drag_threshold;
bool smart_gaps; enum smart_gaps_mode smart_gaps;
int gaps_inner; int gaps_inner;
struct side_gaps gaps_outer; struct side_gaps gaps_outer;
@ -535,12 +548,15 @@ struct sway_config {
struct { struct {
struct border_colors focused; struct border_colors focused;
struct border_colors focused_inactive; struct border_colors focused_inactive;
struct border_colors focused_tab_title;
struct border_colors unfocused; struct border_colors unfocused;
struct border_colors urgent; struct border_colors urgent;
struct border_colors placeholder; struct border_colors placeholder;
float background[4]; float background[4];
} border_colors; } border_colors;
bool has_focused_tab_title;
// floating view // floating view
int32_t floating_maximum_width; int32_t floating_maximum_width;
int32_t floating_maximum_height; int32_t floating_maximum_height;

View file

@ -25,6 +25,8 @@ struct sway_layer_surface {
bool mapped; bool mapped;
struct wlr_box extent; struct wlr_box extent;
enum zwlr_layer_shell_v1_layer layer; enum zwlr_layer_shell_v1_layer layer;
struct wl_list subsurfaces;
}; };
struct sway_layer_popup { struct sway_layer_popup {
@ -44,6 +46,7 @@ struct sway_layer_popup {
struct sway_layer_subsurface { struct sway_layer_subsurface {
struct wlr_subsurface *wlr_subsurface; struct wlr_subsurface *wlr_subsurface;
struct sway_layer_surface *layer_surface; struct sway_layer_surface *layer_surface;
struct wl_list link;
struct wl_listener map; struct wl_listener map;
struct wl_listener unmap; struct wl_listener unmap;

View file

@ -48,7 +48,7 @@ struct sway_output {
struct wl_listener damage_frame; struct wl_listener damage_frame;
struct { struct {
struct wl_signal destroy; struct wl_signal disable;
} events; } events;
struct timespec last_presentation; struct timespec last_presentation;

View file

@ -4,6 +4,7 @@
#include <wayland-server-core.h> #include <wayland-server-core.h>
#include <wlr/backend.h> #include <wlr/backend.h>
#include <wlr/backend/session.h> #include <wlr/backend/session.h>
#include <wlr/render/allocator.h>
#include <wlr/render/wlr_renderer.h> #include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_compositor.h> #include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_data_device.h> #include <wlr/types/wlr_data_device.h>
@ -32,13 +33,16 @@ struct sway_server {
const char *socket; const char *socket;
struct wlr_backend *backend; struct wlr_backend *backend;
struct wlr_backend *noop_backend;
// secondary headless backend used for creating virtual outputs on-the-fly // secondary headless backend used for creating virtual outputs on-the-fly
struct wlr_backend *headless_backend; struct wlr_backend *headless_backend;
struct wlr_renderer *renderer;
struct wlr_allocator *allocator;
struct wlr_compositor *compositor; struct wlr_compositor *compositor;
struct wl_listener compositor_new_surface; struct wl_listener compositor_new_surface;
struct wlr_linux_dmabuf_v1 *linux_dmabuf_v1;
struct wlr_data_device_manager *data_device_manager; struct wlr_data_device_manager *data_device_manager;
struct sway_input_manager *input; struct sway_input_manager *input;
@ -137,6 +141,8 @@ void server_fini(struct sway_server *server);
bool server_start(struct sway_server *server); bool server_start(struct sway_server *server);
void server_run(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_compositor_new_surface(struct wl_listener *listener, void *data);
void handle_new_output(struct wl_listener *listener, void *data); void handle_new_output(struct wl_listener *listener, void *data);

View file

@ -117,12 +117,14 @@ struct sway_container {
struct wlr_texture *title_focused; struct wlr_texture *title_focused;
struct wlr_texture *title_focused_inactive; struct wlr_texture *title_focused_inactive;
struct wlr_texture *title_focused_tab_title;
struct wlr_texture *title_unfocused; struct wlr_texture *title_unfocused;
struct wlr_texture *title_urgent; struct wlr_texture *title_urgent;
list_t *marks; // char * list_t *marks; // char *
struct wlr_texture *marks_focused; struct wlr_texture *marks_focused;
struct wlr_texture *marks_focused_inactive; struct wlr_texture *marks_focused_inactive;
struct wlr_texture *marks_focused_tab_title;
struct wlr_texture *marks_unfocused; struct wlr_texture *marks_unfocused;
struct wlr_texture *marks_urgent; struct wlr_texture *marks_urgent;

View file

@ -31,7 +31,7 @@ struct sway_root {
list_t *scratchpad; // struct sway_container list_t *scratchpad; // struct sway_container
// For when there's no connected outputs // For when there's no connected outputs
struct sway_output *noop_output; struct sway_output *fallback_output;
struct sway_container *fullscreen_global; struct sway_container *fullscreen_global;

View file

@ -5,7 +5,6 @@
#include "list.h" #include "list.h"
#include "pool-buffer.h" #include "pool-buffer.h"
#include "swaynag/types.h" #include "swaynag/types.h"
#include "xdg-output-unstable-v1-client-protocol.h"
#define SWAYNAG_MAX_HEIGHT 500 #define SWAYNAG_MAX_HEIGHT 500
@ -75,13 +74,11 @@ struct swaynag_details {
struct swaynag { struct swaynag {
bool run_display; bool run_display;
int querying_outputs;
struct wl_display *display; struct wl_display *display;
struct wl_compositor *compositor; struct wl_compositor *compositor;
struct wl_seat *seat; struct wl_seat *seat;
struct wl_shm *shm; struct wl_shm *shm;
struct zxdg_output_manager_v1 *xdg_output_manager;
struct wl_list outputs; // swaynag_output::link struct wl_list outputs; // swaynag_output::link
struct wl_list seats; // swaynag_seat::link struct wl_list seats; // swaynag_seat::link
struct swaynag_output *output; struct swaynag_output *output;

View file

@ -1,9 +1,9 @@
project( project(
'sway', 'sway',
'c', 'c',
version: '1.6', version: '1.7',
license: 'MIT', license: 'MIT',
meson_version: '>=0.59.0', meson_version: '>=0.60.0',
default_options: [ default_options: [
'c_std=c11', 'c_std=c11',
'warning_level=2', 'warning_level=2',
@ -37,11 +37,11 @@ endif
jsonc = dependency('json-c', version: '>=0.13') jsonc = dependency('json-c', version: '>=0.13')
pcre = dependency('libpcre') pcre = dependency('libpcre')
wayland_server = dependency('wayland-server') wayland_server = dependency('wayland-server', version: '>=1.20.0')
wayland_client = dependency('wayland-client') wayland_client = dependency('wayland-client')
wayland_cursor = dependency('wayland-cursor') wayland_cursor = dependency('wayland-cursor')
wayland_egl = dependency('wayland-egl') wayland_egl = dependency('wayland-egl')
wayland_protos = dependency('wayland-protocols', version: '>=1.14') wayland_protos = dependency('wayland-protocols', version: '>=1.24')
xkbcommon = dependency('xkbcommon') xkbcommon = dependency('xkbcommon')
cairo = dependency('cairo') cairo = dependency('cairo')
pango = dependency('pango') pango = dependency('pango')
@ -92,18 +92,10 @@ if get_option('sd-bus-provider') == 'auto'
if not get_option('tray').disabled() 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') assert(get_option('auto_features').auto(), 'sd-bus-provider must not be set to auto since auto_features != auto')
endif endif
sdbus = dependency('libsystemd', sdbus = dependency(['libsystemd', 'libelogind'],
required: false, required: false,
version: '>=239', 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() if not sdbus.found()
sdbus = dependency('basu', required: false) sdbus = dependency('basu', required: false)
endif endif
@ -171,8 +163,8 @@ add_project_arguments('-DSYSCONFDIR="/@0@"'.format(join_paths(prefix, sysconfdir
version = '"@0@"'.format(meson.project_version()) version = '"@0@"'.format(meson.project_version())
git = find_program('git', native: true, required: false) git = find_program('git', native: true, required: false)
if git.found() if git.found()
git_commit = run_command([git, 'rev-parse', '--short', 'HEAD']) git_commit = run_command([git, 'rev-parse', '--short', 'HEAD'], check: false)
git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD']) git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD'], check: false)
if git_commit.returncode() == 0 and git_branch.returncode() == 0 if git_commit.returncode() == 0 and git_branch.returncode() == 0
version = '"@0@-@1@ (" __DATE__ ", branch \'@2@\')"'.format( version = '"@0@-@1@ (" __DATE__ ", branch \'@2@\')"'.format(
meson.project_version(), meson.project_version(),

View file

@ -15,6 +15,7 @@ protocols = [
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'], [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/pointer-constraints/pointer-constraints-unstable-v1.xml'],
[wl_protocol_dir, 'unstable/tablet/tablet-unstable-v2.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'], ['wlr-layer-shell-unstable-v1.xml'],
['idle.xml'], ['idle.xml'],
['wlr-input-inhibitor-unstable-v1.xml'], ['wlr-input-inhibitor-unstable-v1.xml'],

View file

@ -51,6 +51,7 @@ static const struct cmd_handler handlers[] = {
{ "client.background", cmd_client_noop }, { "client.background", cmd_client_noop },
{ "client.focused", cmd_client_focused }, { "client.focused", cmd_client_focused },
{ "client.focused_inactive", cmd_client_focused_inactive }, { "client.focused_inactive", cmd_client_focused_inactive },
{ "client.focused_tab_title", cmd_client_focused_tab_title },
{ "client.placeholder", cmd_client_noop }, { "client.placeholder", cmd_client_noop },
{ "client.unfocused", cmd_client_unfocused }, { "client.unfocused", cmd_client_unfocused },
{ "client.urgent", cmd_client_urgent }, { "client.urgent", cmd_client_urgent },

View file

@ -54,7 +54,7 @@ struct cmd_results *bar_cmd_hidden_state(int argc, char **argv) {
} }
const char *state = argv[0]; const char *state = argv[0];
if (config->reading) { if (config->current_bar) {
error = bar_set_hidden_state(config->current_bar, state); error = bar_set_hidden_state(config->current_bar, state);
} else { } else {
const char *id = argc == 2 ? argv[1] : NULL; const char *id = argc == 2 ? argv[1] : NULL;

View file

@ -58,7 +58,7 @@ struct cmd_results *bar_cmd_mode(int argc, char **argv) {
} }
const char *mode = argv[0]; const char *mode = argv[0];
if (config->reading) { if (config->current_bar) {
error = bar_set_mode(config->current_bar, mode); error = bar_set_mode(config->current_bar, mode);
} else { } else {
const char *id = argc == 2 ? argv[1] : NULL; const char *id = argc == 2 ? argv[1] : NULL;

View file

@ -18,6 +18,12 @@ static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name,
return error; 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}; struct border_colors colors = {0};
const char *ind_hex = argc > 3 ? argv[3] : default_indicator; const char *ind_hex = argc > 3 ? argv[3] : default_indicator;
const char *child_hex = argc > 4 ? argv[4] : argv[1]; // def to background 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]); sway_log(SWAY_INFO, "Warning: %s is ignored by sway", argv[-1]);
return cmd_results_new(CMD_SUCCESS, NULL); 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;
}

View file

@ -7,6 +7,7 @@
#include <signal.h> #include <signal.h>
#include "sway/commands.h" #include "sway/commands.h"
#include "sway/config.h" #include "sway/config.h"
#include "sway/server.h"
#include "sway/tree/container.h" #include "sway/tree/container.h"
#include "sway/tree/root.h" #include "sway/tree/root.h"
#include "sway/tree/workspace.h" #include "sway/tree/workspace.h"
@ -53,6 +54,7 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) {
// Fork process // Fork process
if ((pid = fork()) == 0) { if ((pid = fork()) == 0) {
// Fork child process again // Fork child process again
restore_nofile_limit();
setsid(); setsid();
sigset_t set; sigset_t set;
sigemptyset(&set); sigemptyset(&set);

View file

@ -267,6 +267,11 @@ static struct cmd_results *focus_mode(struct sway_workspace *ws,
new_focus = seat_get_focus_inactive_tiling(seat, ws); new_focus = seat_get_focus_inactive_tiling(seat, ws);
} }
if (new_focus) { if (new_focus) {
struct sway_container *new_focus_view =
seat_get_focus_inactive_view(seat, &new_focus->node);
if (new_focus_view) {
new_focus = new_focus_view;
}
seat_set_focus_container(seat, new_focus); seat_set_focus_container(seat, new_focus);
// If we're on the floating layer and the floating container area // 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, ""); return cmd_results_new(CMD_FAILURE, "");
} }
struct sway_node *next_focus = NULL; 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); next_focus = node_get_in_direction_floating(container, seat, direction);
} else { } else {
next_focus = node_get_in_direction_tiling(container, seat, direction, descend); next_focus = node_get_in_direction_tiling(container, seat, direction, descend);

View file

@ -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"); 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 }; struct movement_amount ly = { .amount = 0, .unit = MOVEMENT_UNIT_INVALID };
// Y direction // Y direction
num_consumed_args = parse_movement_amount(argc, argv, &ly); num_consumed_args = parse_movement_amount(argc, argv, &ly);

View file

@ -18,6 +18,7 @@ static const struct cmd_handler output_handlers[] = {
{ "modeline", output_cmd_modeline }, { "modeline", output_cmd_modeline },
{ "pos", output_cmd_position }, { "pos", output_cmd_position },
{ "position", output_cmd_position }, { "position", output_cmd_position },
{ "render_bit_depth", output_cmd_render_bit_depth },
{ "res", output_cmd_mode }, { "res", output_cmd_mode },
{ "resolution", output_cmd_mode }, { "resolution", output_cmd_mode },
{ "scale", output_cmd_scale }, { "scale", output_cmd_scale },
@ -33,9 +34,9 @@ struct cmd_results *cmd_output(int argc, char **argv) {
return error; 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. // 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, return cmd_results_new(CMD_FAILURE,
"Refusing to configure the no op output"); "Refusing to configure the no op output");
} }
@ -52,7 +53,7 @@ struct cmd_results *cmd_output(int argc, char **argv) {
if (!sway_output) { if (!sway_output) {
return cmd_results_new(CMD_FAILURE, "Unknown 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, return cmd_results_new(CMD_FAILURE,
"Refusing to configure the no op output"); "Refusing to configure the no op output");
} }

View file

@ -0,0 +1,29 @@
#include <drm_fourcc.h>
#include <strings.h>
#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;
}

View file

@ -15,7 +15,12 @@ struct cmd_results *cmd_smart_gaps(int argc, char **argv) {
return error; 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(); arrange_root();

View file

@ -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 fs1 = con1->pending.fullscreen_mode;
enum sway_fullscreen_mode fs2 = con2->pending.fullscreen_mode;
if (fs1) { if (fs1) {
container_fullscreen_disable(con1); container_fullscreen_disable(con1);
} }
enum sway_fullscreen_mode fs2 = con2->pending.fullscreen_mode;
if (fs2) { if (fs2) {
container_fullscreen_disable(con2); container_fullscreen_disable(con2);
} }
@ -247,6 +247,9 @@ struct cmd_results *cmd_swap(int argc, char **argv) {
} else if (!current) { } else if (!current) {
error = cmd_results_new(CMD_FAILURE, error = cmd_results_new(CMD_FAILURE,
"Can only swap with containers and views"); "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) } else if (container_has_ancestor(current, other)
|| container_has_ancestor(other, current)) { || container_has_ancestor(other, current)) {
error = cmd_results_new(CMD_FAILURE, error = cmd_results_new(CMD_FAILURE,

View file

@ -266,7 +266,7 @@ static void config_defaults(struct sway_config *config) {
config->tiling_drag = true; config->tiling_drag = true;
config->tiling_drag_threshold = 9; config->tiling_drag_threshold = 9;
config->smart_gaps = false; config->smart_gaps = SMART_GAPS_OFF;
config->gaps_inner = 0; config->gaps_inner = 0;
config->gaps_outer.top = 0; config->gaps_outer.top = 0;
config->gaps_outer.right = 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_edge_borders_smart = ESMART_OFF;
config->hide_lone_tab = false; config->hide_lone_tab = false;
config->has_focused_tab_title = false;
// border colors // border colors
color_to_rgba(config->border_colors.focused.border, 0x4C7899FF); color_to_rgba(config->border_colors.focused.border, 0x4C7899FF);
color_to_rgba(config->border_colors.focused.background, 0x285577FF); color_to_rgba(config->border_colors.focused.background, 0x285577FF);

View file

@ -219,6 +219,8 @@ static void invoke_swaybar(struct bar_config *bar) {
sigprocmask(SIG_SETMASK, &set, NULL); sigprocmask(SIG_SETMASK, &set, NULL);
signal(SIGPIPE, SIG_DFL); signal(SIGPIPE, SIG_DFL);
restore_nofile_limit();
pid = fork(); pid = fork();
if (pid < 0) { if (pid < 0) {
sway_log_errno(SWAY_ERROR, "fork failed"); sway_log_errno(SWAY_ERROR, "fork failed");

View file

@ -1,5 +1,6 @@
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include <assert.h> #include <assert.h>
#include <drm_fourcc.h>
#include <stdbool.h> #include <stdbool.h>
#include <string.h> #include <string.h>
#include <sys/socket.h> #include <sys/socket.h>
@ -67,6 +68,7 @@ struct output_config *new_output_config(const char *name) {
oc->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN; oc->subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
oc->max_render_time = -1; oc->max_render_time = -1;
oc->adaptive_sync = -1; oc->adaptive_sync = -1;
oc->render_bit_depth = RENDER_BIT_DEPTH_DEFAULT;
return oc; return oc;
} }
@ -113,6 +115,9 @@ void merge_output_config(struct output_config *dst, struct output_config *src) {
if (src->adaptive_sync != -1) { if (src->adaptive_sync != -1) {
dst->adaptive_sync = src->adaptive_sync; 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) { if (src->background) {
free(dst->background); free(dst->background);
dst->background = strdup(src->background); dst->background = strdup(src->background);
@ -351,9 +356,26 @@ static int compute_default_scale(struct wlr_output *output) {
return 2; 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, static void queue_output_config(struct output_config *oc,
struct sway_output *output) { struct sway_output *output) {
if (output == root->noop_output) { if (output == root->fallback_output) {
return; return;
} }
@ -437,10 +459,26 @@ static void queue_output_config(struct output_config *oc,
oc->adaptive_sync); oc->adaptive_sync);
wlr_output_enable_adaptive_sync(wlr_output, oc->adaptive_sync == 1); 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) { bool apply_output_config(struct output_config *oc, struct sway_output *output) {
if (output == root->noop_output) { if (output == root->fallback_output) {
return false; 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) { bool test_output_config(struct output_config *oc, struct sway_output *output) {
if (output == root->noop_output) { if (output == root->fallback_output) {
return false; return false;
} }
@ -750,6 +788,8 @@ static bool _spawn_swaybg(char **command) {
sway_log_errno(SWAY_ERROR, "fork failed"); sway_log_errno(SWAY_ERROR, "fork failed");
return false; return false;
} else if (pid == 0) { } else if (pid == 0) {
restore_nofile_limit();
pid = fork(); pid = fork();
if (pid < 0) { if (pid < 0) {
sway_log_errno(SWAY_ERROR, "fork failed"); sway_log_errno(SWAY_ERROR, "fork failed");

View file

@ -352,6 +352,8 @@ static void unmap(struct sway_layer_surface *sway_layer) {
sway_layer->layer_surface->surface, true); 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) { static void handle_destroy(struct wl_listener *listener, void *data) {
struct sway_layer_surface *sway_layer = struct sway_layer_surface *sway_layer =
wl_container_of(listener, sway_layer, destroy); 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) { if (sway_layer->layer_surface->mapped) {
unmap(sway_layer); 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->link);
wl_list_remove(&sway_layer->destroy.link); wl_list_remove(&sway_layer->destroy.link);
wl_list_remove(&sway_layer->map.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); subsurface_damage(subsurface, false);
} }
static void subsurface_handle_destroy(struct wl_listener *listener, static void layer_subsurface_destroy(struct sway_layer_subsurface *subsurface) {
void *data) { wl_list_remove(&subsurface->link);
struct sway_layer_subsurface *subsurface =
wl_container_of(listener, subsurface, destroy);
wl_list_remove(&subsurface->map.link); wl_list_remove(&subsurface->map.link);
wl_list_remove(&subsurface->unmap.link); wl_list_remove(&subsurface->unmap.link);
wl_list_remove(&subsurface->destroy.link); wl_list_remove(&subsurface->destroy.link);
@ -440,6 +445,13 @@ static void subsurface_handle_destroy(struct wl_listener *listener,
free(subsurface); 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( static struct sway_layer_subsurface *create_subsurface(
struct wlr_subsurface *wlr_subsurface, struct wlr_subsurface *wlr_subsurface,
struct sway_layer_surface *layer_surface) { struct sway_layer_surface *layer_surface) {
@ -451,6 +463,7 @@ static struct sway_layer_subsurface *create_subsurface(
subsurface->wlr_subsurface = wlr_subsurface; subsurface->wlr_subsurface = wlr_subsurface;
subsurface->layer_surface = layer_surface; subsurface->layer_surface = layer_surface;
wl_list_insert(&layer_surface->subsurfaces, &subsurface->link);
subsurface->map.notify = subsurface_handle_map; subsurface->map.notify = subsurface_handle_map;
wl_signal_add(&wlr_subsurface->events.map, &subsurface->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; output = ws->output;
} }
} }
if (!output || output == root->noop_output) { if (!output || output == root->fallback_output) {
if (!root->outputs->length) { if (!root->outputs->length) {
sway_log(SWAY_ERROR, sway_log(SWAY_ERROR,
"no output to auto-assign layer surface '%s' to", "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; return;
} }
wl_list_init(&sway_layer->subsurfaces);
sway_layer->surface_commit.notify = handle_surface_commit; sway_layer->surface_commit.notify = handle_surface_commit;
wl_signal_add(&layer_surface->surface->events.commit, wl_signal_add(&layer_surface->surface->events.commit,
&sway_layer->surface_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; struct sway_output *output = layer_surface->output->data;
sway_layer->output_destroy.notify = handle_output_destroy; 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], wl_list_insert(&output->layers[layer_surface->pending.layer],
&sway_layer->link); &sway_layer->link);

View file

@ -5,6 +5,7 @@
#include <time.h> #include <time.h>
#include <wayland-server-core.h> #include <wayland-server-core.h>
#include <wlr/backend/drm.h> #include <wlr/backend/drm.h>
#include <wlr/backend/headless.h>
#include <wlr/render/wlr_renderer.h> #include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_buffer.h> #include <wlr/types/wlr_buffer.h>
#include <wlr/types/wlr_drm_lease_v1.h> #include <wlr/types/wlr_drm_lease_v1.h>
@ -633,21 +634,19 @@ static void damage_surface_iterator(struct sway_output *output,
struct wlr_box box = *_box; struct wlr_box box = *_box;
scale_box(&box, output->wlr_output->scale); scale_box(&box, output->wlr_output->scale);
if (pixman_region32_not_empty(&surface->buffer_damage)) { pixman_region32_t damage;
pixman_region32_t damage; pixman_region32_init(&damage);
pixman_region32_init(&damage); wlr_surface_get_effective_damage(surface, &damage);
wlr_surface_get_effective_damage(surface, &damage); wlr_region_scale(&damage, &damage, output->wlr_output->scale);
wlr_region_scale(&damage, &damage, output->wlr_output->scale); if (ceil(output->wlr_output->scale) > surface->current.scale) {
if (ceil(output->wlr_output->scale) > surface->current.scale) { // When scaling up a surface, it'll become blurry so we need to
// When scaling up a surface, it'll become blurry so we need to // expand the damage region
// expand the damage region wlr_region_expand(&damage, &damage,
wlr_region_expand(&damage, &damage, ceil(output->wlr_output->scale) - surface->current.scale);
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_translate(&damage, box.x, box.y);
wlr_output_damage_add(output->damage, &damage);
pixman_region32_fini(&damage);
if (whole) { if (whole) {
wlr_output_damage_add_box(output->damage, &box); 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; struct sway_output *output;
wl_list_for_each(output, &root->all_outputs, link) { wl_list_for_each(output, &root->all_outputs, link) {
if (output == root->noop_output) { if (output == root->fallback_output) {
continue; continue;
} }
struct wlr_output_configuration_head_v1 *config_head = 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) { static void handle_destroy(struct wl_listener *listener, void *data) {
struct sway_output *output = wl_container_of(listener, output, destroy); struct sway_output *output = wl_container_of(listener, output, destroy);
struct sway_server *server = output->server; struct sway_server *server = output->server;
wl_signal_emit(&output->events.destroy, output); output_begin_destroy(output);
if (output->enabled) { if (output->enabled) {
output_disable(output); output_disable(output);
} }
output_begin_destroy(output);
wl_list_remove(&output->link);
wl_list_remove(&output->destroy.link); wl_list_remove(&output->destroy.link);
wl_list_remove(&output->commit.link); wl_list_remove(&output->commit.link);
wl_list_remove(&output->mode.link); wl_list_remove(&output->mode.link);
wl_list_remove(&output->present.link); wl_list_remove(&output->present.link);
output->wlr_output->data = NULL;
output->wlr_output = NULL;
transaction_commit_dirty(); transaction_commit_dirty();
update_output_manager_config(server); 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; output->refresh_nsec = output_event->refresh;
} }
static unsigned int last_headless_num = 0;
void handle_new_output(struct wl_listener *listener, void *data) { void handle_new_output(struct wl_listener *listener, void *data) {
struct sway_server *server = wl_container_of(listener, server, new_output); struct sway_server *server = wl_container_of(listener, server, new_output);
struct wlr_output *wlr_output = data; 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)", sway_log(SWAY_DEBUG, "New output %p: %s (non-desktop: %d)",
wlr_output, wlr_output->name, wlr_output->non_desktop); wlr_output, wlr_output->name, wlr_output->non_desktop);
@ -850,6 +866,12 @@ void handle_new_output(struct wl_listener *listener, void *data) {
return; 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); struct sway_output *output = output_create(wlr_output);
if (!output) { if (!output) {
return; return;

View file

@ -52,7 +52,7 @@ static int scale_length(int length, int offset, float scale) {
static void scissor_output(struct wlr_output *wlr_output, static void scissor_output(struct wlr_output *wlr_output,
pixman_box32_t *rect) { pixman_box32_t *rect) {
struct wlr_renderer *renderer = wlr_backend_get_renderer(wlr_output->backend); struct wlr_renderer *renderer = wlr_output->renderer;
assert(renderer); assert(renderer);
struct wlr_box box = { 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, pixman_region32_t *output_damage, struct wlr_texture *texture,
const struct wlr_fbox *src_box, const struct wlr_box *dst_box, const struct wlr_fbox *src_box, const struct wlr_box *dst_box,
const float matrix[static 9], float alpha) { const float matrix[static 9], float alpha) {
struct wlr_renderer *renderer = struct wlr_renderer *renderer = wlr_output->renderer;
wlr_backend_get_renderer(wlr_output->backend);
struct sway_output *output = wlr_output->data; struct sway_output *output = wlr_output->data;
pixman_region32_t damage; 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, pixman_region32_t *output_damage, const struct wlr_box *_box,
float color[static 4]) { float color[static 4]) {
struct wlr_output *wlr_output = output->wlr_output; struct wlr_output *wlr_output = output->wlr_output;
struct wlr_renderer *renderer = struct wlr_renderer *renderer = wlr_output->renderer;
wlr_backend_get_renderer(wlr_output->backend);
struct wlr_box box; struct wlr_box box;
memcpy(&box, _box, sizeof(struct wlr_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. * 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; colors = &config->border_colors.focused;
title_texture = child->title_focused; title_texture = child->title_focused;
marks_texture = child->marks_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) { } else if (child == parent->active_child) {
colors = &config->border_colors.focused_inactive; colors = &config->border_colors.focused_inactive;
title_texture = child->title_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; colors = &config->border_colors.focused;
title_texture = child->title_focused; title_texture = child->title_focused;
marks_texture = child->marks_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; colors = &config->border_colors.focused_inactive;
title_texture = child->title_focused_inactive; title_texture = child->title_focused_inactive;
marks_texture = child->marks_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, void output_render(struct sway_output *output, struct timespec *when,
pixman_region32_t *damage) { pixman_region32_t *damage) {
struct wlr_output *wlr_output = output->wlr_output; struct wlr_output *wlr_output = output->wlr_output;
struct wlr_renderer *renderer = output->server->renderer;
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 sway_workspace *workspace = output->current.active_workspace; struct sway_workspace *workspace = output->current.active_workspace;
if (workspace == NULL) { if (workspace == NULL) {

View file

@ -402,7 +402,7 @@ static void transaction_commit(struct sway_transaction *transaction) {
struct sway_transaction_instruction *instruction = struct sway_transaction_instruction *instruction =
transaction->instructions->items[i]; transaction->instructions->items[i];
struct sway_node *node = instruction->node; 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); !view_is_visible(node->sway_container->view);
if (should_configure(node, instruction)) { if (should_configure(node, instruction)) {
instruction->serial = view_configure(node->sway_container->view, instruction->serial = view_configure(node->sway_container->view,

View file

@ -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 // the output box expressed in the coordinate system of the toplevel parent
// of the popup // of the popup
struct wlr_box output_toplevel_sx_box = { struct wlr_box output_toplevel_sx_box = {
.x = output->lx - view->container->pending.content_x, .x = output->lx - view->container->pending.content_x + view->geometry.x,
.y = output->ly - view->container->pending.content_y, .y = output->ly - view->container->pending.content_y + view->geometry.y,
.width = output->width, .width = output->width,
.height = output->height, .height = output->height,
}; };

View file

@ -436,6 +436,8 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&xwayland_view->commit.link); 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->destroy.link);
wl_list_remove(&xwayland_view->request_configure.link); wl_list_remove(&xwayland_view->request_configure.link);
wl_list_remove(&xwayland_view->request_fullscreen.link); wl_list_remove(&xwayland_view->request_fullscreen.link);

View file

@ -83,7 +83,28 @@ static struct wlr_surface *layer_surface_popup_at(struct sway_output *output,
struct sway_node *node_at_coords( struct sway_node *node_at_coords(
struct sway_seat *seat, double lx, double ly, struct sway_seat *seat, double lx, double ly,
struct wlr_surface **surface, double *sx, double *sy) { 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 #if HAVE_XWAYLAND
struct wl_list *unmanaged = &root->xwayland_unmanaged; struct wl_list *unmanaged = &root->xwayland_unmanaged;
struct sway_xwayland_unmanaged *unmanaged_surface; struct sway_xwayland_unmanaged *unmanaged_surface;
@ -101,19 +122,6 @@ struct sway_node *node_at_coords(
} }
} }
#endif #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) { if (root->fullscreen_global) {
// Try fullscreen container // Try fullscreen container
@ -131,11 +139,6 @@ struct sway_node *node_at_coords(
return NULL; 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) { if (ws->fullscreen) {
// Try transient containers // Try transient containers
for (int i = 0; i < ws->floating->length; ++i) { 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( struct sway_cursor *cursor = wl_container_of(
listener, cursor, pinch_begin); listener, cursor, pinch_begin);
struct wlr_event_pointer_pinch_begin *event = data; struct wlr_event_pointer_pinch_begin *event = data;
cursor_handle_activity_from_device(cursor, event->device);
wlr_pointer_gestures_v1_send_pinch_begin( wlr_pointer_gestures_v1_send_pinch_begin(
cursor->pointer_gestures, cursor->seat->wlr_seat, cursor->pointer_gestures, cursor->seat->wlr_seat,
event->time_msec, event->fingers); 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( struct sway_cursor *cursor = wl_container_of(
listener, cursor, pinch_update); listener, cursor, pinch_update);
struct wlr_event_pointer_pinch_update *event = data; struct wlr_event_pointer_pinch_update *event = data;
cursor_handle_activity_from_device(cursor, event->device);
wlr_pointer_gestures_v1_send_pinch_update( wlr_pointer_gestures_v1_send_pinch_update(
cursor->pointer_gestures, cursor->seat->wlr_seat, cursor->pointer_gestures, cursor->seat->wlr_seat,
event->time_msec, event->dx, event->dy, 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( struct sway_cursor *cursor = wl_container_of(
listener, cursor, pinch_end); listener, cursor, pinch_end);
struct wlr_event_pointer_pinch_end *event = data; struct wlr_event_pointer_pinch_end *event = data;
cursor_handle_activity_from_device(cursor, event->device);
wlr_pointer_gestures_v1_send_pinch_end( wlr_pointer_gestures_v1_send_pinch_end(
cursor->pointer_gestures, cursor->seat->wlr_seat, cursor->pointer_gestures, cursor->seat->wlr_seat,
event->time_msec, event->cancelled); 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( struct sway_cursor *cursor = wl_container_of(
listener, cursor, swipe_begin); listener, cursor, swipe_begin);
struct wlr_event_pointer_swipe_begin *event = data; struct wlr_event_pointer_swipe_begin *event = data;
cursor_handle_activity_from_device(cursor, event->device);
wlr_pointer_gestures_v1_send_swipe_begin( wlr_pointer_gestures_v1_send_swipe_begin(
cursor->pointer_gestures, cursor->seat->wlr_seat, cursor->pointer_gestures, cursor->seat->wlr_seat,
event->time_msec, event->fingers); 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( struct sway_cursor *cursor = wl_container_of(
listener, cursor, swipe_update); listener, cursor, swipe_update);
struct wlr_event_pointer_swipe_update *event = data; struct wlr_event_pointer_swipe_update *event = data;
cursor_handle_activity_from_device(cursor, event->device);
wlr_pointer_gestures_v1_send_swipe_update( wlr_pointer_gestures_v1_send_swipe_update(
cursor->pointer_gestures, cursor->seat->wlr_seat, cursor->pointer_gestures, cursor->seat->wlr_seat,
event->time_msec, event->dx, event->dy); 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( struct sway_cursor *cursor = wl_container_of(
listener, cursor, swipe_end); listener, cursor, swipe_end);
struct wlr_event_pointer_swipe_end *event = data; struct wlr_event_pointer_swipe_end *event = data;
cursor_handle_activity_from_device(cursor, event->device);
wlr_pointer_gestures_v1_send_swipe_end( wlr_pointer_gestures_v1_send_swipe_end(
cursor->pointer_gestures, cursor->seat->wlr_seat, cursor->pointer_gestures, cursor->seat->wlr_seat,
event->time_msec, event->cancelled); event->time_msec, event->cancelled);

View file

@ -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) { static void seat_node_destroy(struct sway_seat_node *seat_node) {
wl_list_remove(&seat_node->destroy.link); wl_list_remove(&seat_node->destroy.link);
wl_list_remove(&seat_node->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); free(seat_node);
} }
@ -1415,9 +1425,8 @@ struct sway_node *seat_get_focus(struct sway_seat *seat) {
if (!seat->has_focus) { if (!seat->has_focus) {
return NULL; return NULL;
} }
if (wl_list_empty(&seat->focus_stack)) { sway_assert(!wl_list_empty(&seat->focus_stack),
return NULL; "focus_stack is empty, but has_focus is true");
}
struct sway_seat_node *current = struct sway_seat_node *current =
wl_container_of(seat->focus_stack.next, current, link); wl_container_of(seat->focus_stack.next, current, link);
return current->node; return current->node;

View file

@ -80,17 +80,25 @@ static void handle_pointer_motion(struct sway_seat *seat, uint32_t time_msec) {
double height = e->ref_height + grow_height; double height = e->ref_height + grow_height;
int min_width, max_width, min_height, max_height; int min_width, max_width, min_height, max_height;
floating_calculate_constraints(&min_width, &max_width, floating_calculate_constraints(&min_width, &max_width,
&min_height, &max_height); &min_height, &max_height);
width = fmax(min_width + border_width, fmin(width, max_width)); width = fmin(width, max_width - border_width);
height = fmax(min_height + border_height, fmin(height, max_height)); 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 // Apply the view's min/max size
if (con->view) { if (con->view) {
double view_min_width, view_max_width, view_min_height, view_max_height; 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_get_constraints(con->view, &view_min_width, &view_max_width,
&view_min_height, &view_max_height); &view_min_height, &view_max_height);
width = fmax(view_min_width + border_width, fmin(width, view_max_width)); width = fmin(width, view_max_width - border_width);
height = fmax(view_min_height + border_height, fmin(height, view_max_height)); 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);
} }

View file

@ -687,7 +687,7 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
} }
struct sway_output *output; struct sway_output *output;
wl_list_for_each(output, &root->all_outputs, link) { 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, json_object_array_add(outputs,
ipc_json_describe_disabled_output(output)); ipc_json_describe_disabled_output(output));
} }

View file

@ -6,6 +6,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/resource.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/wait.h> #include <sys/wait.h>
@ -27,6 +28,7 @@
static bool terminate_request = false; static bool terminate_request = false;
static int exit_value = 0; static int exit_value = 0;
static struct rlimit original_nofile_rlimit = {0};
struct sway_server server = {0}; struct sway_server server = {0};
struct sway_debug debug = {0}; struct sway_debug debug = {0};
@ -63,7 +65,7 @@ void detect_proprietary(int allow_unsupported_gpu) {
sway_log(SWAY_ERROR, sway_log(SWAY_ERROR,
"Proprietary Nvidia drivers are NOT supported. " "Proprietary Nvidia drivers are NOT supported. "
"Use Nouveau. To launch sway anyway, launch with " "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); exit(EXIT_FAILURE);
} }
break; break;
@ -151,6 +153,9 @@ static void log_kernel(void) {
static bool drop_permissions(void) { static bool drop_permissions(void) {
if (getuid() != geteuid() || getgid() != getegid()) { 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. // Set the gid and uid in the correct order.
if (setgid(getgid()) != 0) { if (setgid(getgid()) != 0) {
sway_log(SWAY_ERROR, "Unable to drop root group, refusing to start"); sway_log(SWAY_ERROR, "Unable to drop root group, refusing to start");
@ -169,6 +174,33 @@ static bool drop_permissions(void) {
return true; 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) { void enable_debug_flag(const char *flag) {
if (strcmp(flag, "damage=highlight") == 0) { if (strcmp(flag, "damage=highlight") == 0) {
debug.damage = DAMAGE_HIGHLIGHT; debug.damage = DAMAGE_HIGHLIGHT;
@ -220,7 +252,6 @@ int main(int argc, char **argv) {
{"verbose", no_argument, NULL, 'V'}, {"verbose", no_argument, NULL, 'V'},
{"get-socketpath", no_argument, NULL, 'p'}, {"get-socketpath", no_argument, NULL, 'p'},
{"unsupported-gpu", no_argument, NULL, 'u'}, {"unsupported-gpu", no_argument, NULL, 'u'},
{"my-next-gpu-wont-be-nvidia", no_argument, NULL, 'u'},
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
@ -314,7 +345,6 @@ int main(int argc, char **argv) {
log_kernel(); log_kernel();
log_distro(); log_distro();
log_env(); log_env();
detect_proprietary(allow_unsupported_gpu);
if (optind < argc) { // Behave as IPC client if (optind < argc) { // Behave as IPC client
if (optind != 1) { if (optind != 1) {
@ -341,6 +371,8 @@ int main(int argc, char **argv) {
return 0; return 0;
} }
detect_proprietary(allow_unsupported_gpu);
if (!server_privileged_prepare(&server)) { if (!server_privileged_prepare(&server)) {
return 1; return 1;
} }
@ -350,6 +382,8 @@ int main(int argc, char **argv) {
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
increase_nofile_limit();
// handle SIGTERM signals // handle SIGTERM signals
signal(SIGTERM, sig_handler); signal(SIGTERM, sig_handler);
signal(SIGINT, sig_handler); signal(SIGINT, sig_handler);

View file

@ -188,6 +188,7 @@ sway_sources = files(
'commands/output/max_render_time.c', 'commands/output/max_render_time.c',
'commands/output/mode.c', 'commands/output/mode.c',
'commands/output/position.c', 'commands/output/position.c',
'commands/output/render_bit_depth.c',
'commands/output/scale.c', 'commands/output/scale.c',
'commands/output/scale_filter.c', 'commands/output/scale_filter.c',
'commands/output/subpixel.c', 'commands/output/subpixel.c',

View file

@ -7,17 +7,18 @@
#include <wlr/backend.h> #include <wlr/backend.h>
#include <wlr/backend/headless.h> #include <wlr/backend/headless.h>
#include <wlr/backend/multi.h> #include <wlr/backend/multi.h>
#include <wlr/backend/noop.h>
#include <wlr/backend/session.h> #include <wlr/backend/session.h>
#include <wlr/config.h> #include <wlr/config.h>
#include <wlr/render/wlr_renderer.h> #include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_compositor.h> #include <wlr/types/wlr_compositor.h>
#include <wlr/types/wlr_data_control_v1.h> #include <wlr/types/wlr_data_control_v1.h>
#include <wlr/types/wlr_drm_lease_v1.h> #include <wlr/types/wlr_drm_lease_v1.h>
#include <wlr/types/wlr_drm.h>
#include <wlr/types/wlr_export_dmabuf_v1.h> #include <wlr/types/wlr_export_dmabuf_v1.h>
#include <wlr/types/wlr_gamma_control_v1.h> #include <wlr/types/wlr_gamma_control_v1.h>
#include <wlr/types/wlr_idle.h> #include <wlr/types/wlr_idle.h>
#include <wlr/types/wlr_layer_shell_v1.h> #include <wlr/types/wlr_layer_shell_v1.h>
#include <wlr/types/wlr_linux_dmabuf_v1.h>
#include <wlr/types/wlr_pointer_constraints_v1.h> #include <wlr/types/wlr_pointer_constraints_v1.h>
#include <wlr/types/wlr_primary_selection_v1.h> #include <wlr/types/wlr_primary_selection_v1.h>
#include <wlr/types/wlr_relative_pointer_v1.h> #include <wlr/types/wlr_relative_pointer_v1.h>
@ -73,12 +74,29 @@ static void handle_drm_lease_request(struct wl_listener *listener, void *data) {
bool server_init(struct sway_server *server) { bool server_init(struct sway_server *server) {
sway_log(SWAY_DEBUG, "Initializing Wayland server"); sway_log(SWAY_DEBUG, "Initializing Wayland server");
struct wlr_renderer *renderer = wlr_backend_get_renderer(server->backend); server->renderer = wlr_renderer_autocreate(server->backend);
assert(renderer); 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; server->compositor_new_surface.notify = handle_compositor_new_surface;
wl_signal_add(&server->compositor->events.new_surface, wl_signal_add(&server->compositor->events.new_surface,
&server->compositor_new_surface); &server->compositor_new_surface);
@ -206,20 +224,20 @@ bool server_init(struct sway_server *server) {
return false; return false;
} }
server->noop_backend = wlr_noop_backend_create(server->wl_display); server->headless_backend = wlr_headless_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);
if (!server->headless_backend) { if (!server->headless_backend) {
sway_log(SWAY_INFO, "Failed to create secondary headless backend, " sway_log(SWAY_ERROR, "Failed to create secondary headless backend");
"starting without it"); wlr_backend_destroy(server->backend);
return false;
} else { } else {
wlr_multi_backend_add(server->backend, server->headless_backend); 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 // This may have been set already via -Dtxn-timeout
if (!server->txn_timeout_ms) { if (!server->txn_timeout_ms) {
server->txn_timeout_ms = 200; server->txn_timeout_ms = 200;
@ -276,6 +294,7 @@ bool server_start(struct sway_server *server) {
wlr_backend_destroy(server->backend); wlr_backend_destroy(server->backend);
return false; return false;
} }
return true; return true;
} }

View file

@ -157,6 +157,21 @@ must be separated by one space. For example:
adaptive sync can improve latency, but can cause flickering on some adaptive sync can improve latency, but can cause flickering on some
hardware. hardware.
*output* <name> 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 # SEE ALSO
*sway*(5) *sway-input*(5) *sway*(5) *sway-input*(5)

View file

@ -499,6 +499,12 @@ runtime.
*client.focused_inactive* *client.focused_inactive*
The most recently focused view within a container which is not focused. 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* *client.placeholder*
Ignored (present for i3 compatibility). Ignored (present for i3 compatibility).
@ -554,6 +560,12 @@ The default colors are:
: #ffffff : #ffffff
: #484e50 : #484e50
: #5f676a : #5f676a
| *focused_tab_title*
: #333333
: #5f676a
: #ffffff
: n/a
: n/a
| *unfocused* | *unfocused*
: #333333 : #333333
: #222222 : #222222
@ -692,9 +704,10 @@ The default colors are:
borders will only be enabled if the workspace has more than one visible borders will only be enabled if the workspace has more than one visible
child and gaps equal to zero. 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 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] <identifier> *mark* --add|--replace [--toggle] <identifier>
Marks are arbitrary labels that can be used to identify certain windows and Marks are arbitrary labels that can be used to identify certain windows and

View file

@ -64,6 +64,8 @@ bool swaynag_spawn(const char *swaynag_command,
sway_log(SWAY_ERROR, "Failed to create fork for swaynag"); sway_log(SWAY_ERROR, "Failed to create fork for swaynag");
goto failed; goto failed;
} else if (pid == 0) { } else if (pid == 0) {
restore_nofile_limit();
pid = fork(); pid = fork();
if (pid < 0) { if (pid < 0) {
sway_log_errno(SWAY_ERROR, "fork failed"); sway_log_errno(SWAY_ERROR, "fork failed");

View file

@ -5,8 +5,12 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <strings.h> #include <strings.h>
#include <sys/stat.h>
#include <wayland-server-core.h> #include <wayland-server-core.h>
#include <wlr/types/wlr_linux_dmabuf_v1.h>
#include <wlr/types/wlr_output_layout.h> #include <wlr/types/wlr_output_layout.h>
#include <wlr/render/drm_format_set.h>
#include "linux-dmabuf-unstable-v1-protocol.h"
#include "cairo_util.h" #include "cairo_util.h"
#include "pango.h" #include "pango.h"
#include "sway/config.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_focused_inactive);
wlr_texture_destroy(con->title_unfocused); wlr_texture_destroy(con->title_unfocused);
wlr_texture_destroy(con->title_urgent); wlr_texture_destroy(con->title_urgent);
wlr_texture_destroy(con->title_focused_tab_title);
list_free(con->pending.children); list_free(con->pending.children);
list_free(con->current.children); list_free(con->current.children);
list_free(con->outputs); 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_focused_inactive);
wlr_texture_destroy(con->marks_unfocused); wlr_texture_destroy(con->marks_unfocused);
wlr_texture_destroy(con->marks_urgent); wlr_texture_destroy(con->marks_urgent);
wlr_texture_destroy(con->marks_focused_tab_title);
if (con->view) { if (con->view && con->view->container == con) {
if (con->view->container == con) { con->view->container = NULL;
con->view->container = NULL;
}
if (con->view->destroying) { if (con->view->destroying) {
view_destroy(con->view); 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) { static bool surface_is_popup(struct wlr_surface *surface) {
if (wlr_surface_is_xdg_surface(surface)) { while (!wlr_surface_is_xdg_surface(surface)) {
struct wlr_xdg_surface *xdg_surface = if (!wlr_surface_is_subsurface(surface)) {
wlr_xdg_surface_from_wlr_surface(surface); return false;
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;
} }
return false; struct wlr_subsurface *subsurface =
wlr_subsurface_from_wlr_surface(surface);
surface = subsurface->parent;
} }
struct wlr_xdg_surface *xdg_surface =
return false; 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, 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_surface_t *surface = cairo_image_surface_create(
CAIRO_FORMAT_ARGB32, width, height); 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_t *cairo = cairo_create(surface);
cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST); cairo_set_antialias(cairo, CAIRO_ANTIALIAS_BEST);
cairo_set_font_options(cairo, fo); cairo_set_font_options(cairo, fo);
@ -549,8 +558,7 @@ static void render_titlebar_text_texture(struct sway_output *output,
cairo_surface_flush(surface); cairo_surface_flush(surface);
unsigned char *data = cairo_image_surface_get_data(surface); unsigned char *data = cairo_image_surface_get_data(surface);
int stride = cairo_image_surface_get_stride(surface); int stride = cairo_image_surface_get_stride(surface);
struct wlr_renderer *renderer = wlr_backend_get_renderer( struct wlr_renderer *renderer = output->wlr_output->renderer;
output->wlr_output->backend);
*texture = wlr_texture_from_pixels( *texture = wlr_texture_from_pixels(
renderer, DRM_FORMAT_ARGB8888, stride, width, height, data); renderer, DRM_FORMAT_ARGB8888, stride, width, height, data);
cairo_surface_destroy(surface); cairo_surface_destroy(surface);
@ -585,6 +593,8 @@ void container_update_title_textures(struct sway_container *container) {
&config->border_colors.unfocused); &config->border_colors.unfocused);
update_title_texture(container, &container->title_urgent, update_title_texture(container, &container->title_urgent,
&config->border_colors.urgent); &config->border_colors.urgent);
update_title_texture(container, &container->title_focused_tab_title,
&config->border_colors.focused_tab_title);
container_damage_whole(container); 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) { static void set_fullscreen(struct sway_container *con, bool enable) {
if (!con->view) { if (!con->view) {
return; return;
@ -1061,6 +1081,75 @@ static void set_fullscreen(struct sway_container *con, bool enable) {
con->view->foreign_toplevel, 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) { 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); &config->border_colors.unfocused);
update_marks_texture(con, &con->marks_urgent, update_marks_texture(con, &con->marks_urgent,
&config->border_colors.urgent); &config->border_colors.urgent);
update_marks_texture(con, &con->marks_focused_tab_title,
&config->border_colors.focused_tab_title);
container_damage_whole(con); container_damage_whole(con);
} }

View file

@ -56,8 +56,8 @@ static void restore_workspaces(struct sway_output *output) {
} }
// Saved workspaces // Saved workspaces
while (root->noop_output->workspaces->length) { while (root->fallback_output->workspaces->length) {
struct sway_workspace *ws = root->noop_output->workspaces->items[0]; struct sway_workspace *ws = root->fallback_output->workspaces->items[0];
workspace_detach(ws); workspace_detach(ws);
output_add_workspace(output, 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->detected_subpixel = wlr_output->subpixel;
output->scale_filter = SCALE_FILTER_NEAREST; 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); wl_list_insert(&root->all_outputs, &output->link);
@ -192,7 +192,7 @@ static void output_evacuate(struct sway_output *output) {
new_output = fallback_output; new_output = fallback_output;
} }
if (!new_output) { if (!new_output) {
new_output = root->noop_output; new_output = root->fallback_output;
} }
struct sway_workspace *new_output_ws = 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); 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); output_evacuate(output);
@ -286,13 +286,10 @@ void output_begin_destroy(struct sway_output *output) {
return; return;
} }
sway_log(SWAY_DEBUG, "Destroying output '%s'", output->wlr_output->name); sway_log(SWAY_DEBUG, "Destroying output '%s'", output->wlr_output->name);
wl_signal_emit(&output->node.events.destroy, &output->node);
output->node.destroying = true; output->node.destroying = true;
node_set_dirty(&output->node); 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) { struct sway_output *output_from_wlr_output(struct wlr_output *output) {

View file

@ -374,8 +374,8 @@ void root_for_each_container(void (*f)(struct sway_container *con, void *data),
} }
// Saved workspaces // Saved workspaces
for (int i = 0; i < root->noop_output->workspaces->length; ++i) { for (int i = 0; i < root->fallback_output->workspaces->length; ++i) {
struct sway_workspace *ws = root->noop_output->workspaces->items[i]; struct sway_workspace *ws = root->fallback_output->workspaces->items[i];
workspace_for_each_container(ws, f, data); workspace_for_each_container(ws, f, data);
} }
} }
@ -427,8 +427,8 @@ struct sway_container *root_find_container(
} }
// Saved workspaces // Saved workspaces
for (int i = 0; i < root->noop_output->workspaces->length; ++i) { for (int i = 0; i < root->fallback_output->workspaces->length; ++i) {
struct sway_workspace *ws = root->noop_output->workspaces->items[i]; struct sway_workspace *ws = root->fallback_output->workspaces->items[i];
if ((result = workspace_find_container(ws, test, data))) { if ((result = workspace_find_container(ws, test, data))) {
return result; return result;
} }

View file

@ -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_seat *seat = input_manager_current_seat();
struct sway_node *node = ws ? seat_get_focus_inactive(seat, &ws->node) struct sway_node *node =
: seat_get_focus_inactive(seat, &root->node); seat_get_focus_inactive(seat, ws ? &ws->node : &root->node);
struct sway_container *target_sibling = node->type == N_CONTAINER ? struct sway_container *target_sibling = NULL;
node->sway_container : 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 = view->foreign_toplevel =
wlr_foreign_toplevel_handle_v1_create(server.foreign_toplevel_manager); 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); &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; struct sway_container *container = view->container;
if (target_sibling) { if (target_sibling) {
container_add_sibling(target_sibling, container, 1); 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); wl_signal_add(&view->events.unmap, &child->view_unmap);
child->view_unmap.notify = view_child_handle_view_unmap; child->view_unmap.notify = view_child_handle_view_unmap;
struct sway_workspace *workspace = child->view->container->pending.workspace; struct sway_container *container = child->view->container;
if (workspace) { if (container != NULL) {
wlr_surface_send_enter(child->surface, workspace->output->wlr_output); 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); view_child_init_subsurfaces(child, surface);

View file

@ -50,8 +50,8 @@ struct sway_output *workspace_get_initial_output(const char *name) {
} else if (focus && focus->type == N_CONTAINER) { } else if (focus && focus->type == N_CONTAINER) {
return focus->sway_container->pending.workspace->output; return focus->sway_container->pending.workspace->output;
} }
// Fallback to the first output or noop output for headless // Fallback to the first output or the headless output
return root->outputs->length ? root->outputs->items[0] : root->noop_output; return root->outputs->length ? root->outputs->items[0] : root->fallback_output;
} }
struct sway_workspace *workspace_create(struct sway_output *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; 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) { void workspace_add_gaps(struct sway_workspace *ws) {
if (config->smart_gaps) { if (config->smart_gaps == SMART_GAPS_ON
struct sway_seat *seat = input_manager_get_default_seat(); && workspace_has_single_visible_container(ws)) {
struct sway_container *focus = ws->current_gaps.top = 0;
seat_get_focus_inactive_tiling(seat, ws); ws->current_gaps.right = 0;
if (focus && !focus->view) { ws->current_gaps.bottom = 0;
focus = seat_get_focus_inactive_view(seat, &focus->node); ws->current_gaps.left = 0;
} return;
if (focus && focus->view && view_ancestor_is_only_visible(focus->view)) { }
ws->current_gaps.top = 0;
ws->current_gaps.right = 0; if (config->smart_gaps == SMART_GAPS_INVERSE_OUTER
ws->current_gaps.bottom = 0; && !workspace_has_single_visible_container(ws)) {
ws->current_gaps.left = 0; ws->current_gaps.top = 0;
return; 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 // 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.top = fmax(0, ws->current_gaps.top + ws->gaps_inner);
ws->current_gaps.right = fmax(0, ws->current_gaps.right + ws->gaps_inner); ws->current_gaps.right = fmax(0, ws->current_gaps.right + ws->gaps_inner);

View file

@ -54,7 +54,6 @@ static void swaybar_output_free(struct swaybar_output *output) {
if (output->input_region != NULL) { if (output->input_region != NULL) {
wl_region_destroy(output->input_region); wl_region_destroy(output->input_region);
} }
zxdg_output_v1_destroy(output->xdg_output);
wl_output_destroy(output->output); wl_output_destroy(output->output);
destroy_buffer(&output->buffers[0]); destroy_buffer(&output->buffers[0]);
destroy_buffer(&output->buffers[1]); destroy_buffer(&output->buffers[1]);
@ -172,7 +171,7 @@ bool determine_bar_visibility(struct swaybar *bar, bool moving_layer) {
if (bar->status) { if (bar->status) {
sway_log(SWAY_DEBUG, "Sending %s signal to status command", sway_log(SWAY_DEBUG, "Sending %s signal to status command",
visible ? "cont" : "stop"); visible ? "cont" : "stop");
kill(bar->status->pid, visible ? kill(-bar->status->pid, visible ?
bar->status->cont_signal : bar->status->stop_signal); bar->status->cont_signal : bar->status->stop_signal);
} }
} }

View file

@ -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 // 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 // we can't pass INT_MAX here because json-c (as of this writing) prefaults
// all the memory for its stack. // 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) { if (!tok) {
sway_log_errno(SWAY_ERROR, "failed to create tokener"); sway_log_errno(SWAY_ERROR, "failed to create tokener");
free_ipc_response(resp); free_ipc_response(resp);

View file

@ -117,11 +117,11 @@ bool status_handle_readable(struct status_line *status) {
status->text = status->buffer; status->text = status->buffer;
// intentional fall-through // intentional fall-through
case PROTOCOL_TEXT: case PROTOCOL_TEXT:
errno = 0;
while (true) { while (true) {
if (status->buffer[read_bytes - 1] == '\n') { if (status->buffer[read_bytes - 1] == '\n') {
status->buffer[read_bytes - 1] = '\0'; status->buffer[read_bytes - 1] = '\0';
} }
errno = 0;
read_bytes = getline(&status->buffer, read_bytes = getline(&status->buffer,
&status->buffer_size, status->read); &status->buffer_size, status->read);
if (errno == EAGAIN) { if (errno == EAGAIN) {
@ -157,7 +157,12 @@ struct status_line *status_line_init(char *cmd) {
assert(!getenv("WAYLAND_SOCKET") && "display must be initialized before " assert(!getenv("WAYLAND_SOCKET") && "display must be initialized before "
" starting `status-command`; WAYLAND_SOCKET should not be set"); " starting `status-command`; WAYLAND_SOCKET should not be set");
status->pid = fork(); 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); dup2(pipe_read_fd[1], STDOUT_FILENO);
close(pipe_read_fd[0]); close(pipe_read_fd[0]);
close(pipe_read_fd[1]); 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) { void status_line_free(struct status_line *status) {
status_line_close_fds(status); status_line_close_fds(status);
kill(status->pid, status->cont_signal); kill(-status->pid, status->cont_signal);
kill(status->pid, SIGTERM); kill(-status->pid, SIGTERM);
waitpid(status->pid, NULL, 0); waitpid(status->pid, NULL, 0);
if (status->protocol == PROTOCOL_I3BAR) { if (status->protocol == PROTOCOL_I3BAR) {
struct i3bar_block *block, *tmp; struct i3bar_block *block, *tmp;

View file

@ -493,24 +493,36 @@ uint32_t render_sni(cairo_t *cairo, struct swaybar_output *output, double *x,
cairo_destroy(cairo_icon); cairo_destroy(cairo_icon);
} }
int padded_size = icon_size + 2*padding; double descaled_padding = (double)padding / output->scale;
*x -= padded_size; double descaled_icon_size = (double)icon_size / output->scale;
int y = floor((height - padded_size) / 2.0);
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_operator_t op = cairo_get_operator(cairo);
cairo_set_operator(cairo, CAIRO_OPERATOR_OVER); 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_fill(cairo);
cairo_set_operator(cairo, op); cairo_set_operator(cairo, op);
cairo_pattern_destroy(icon_pattern);
cairo_surface_destroy(icon); cairo_surface_destroy(icon);
struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot)); struct swaybar_hotspot *hotspot = calloc(1, sizeof(struct swaybar_hotspot));
hotspot->x = *x; hotspot->x = *x;
hotspot->y = 0; hotspot->y = 0;
hotspot->width = height; hotspot->width = size;
hotspot->height = height; hotspot->height = output->height;
hotspot->callback = icon_hotspot_callback; hotspot->callback = icon_hotspot_callback;
hotspot->destroy = free; hotspot->destroy = free;
hotspot->data = strdup(sni->watcher_id); hotspot->data = strdup(sni->watcher_id);

View file

@ -116,8 +116,8 @@ uint32_t render_tray(cairo_t *cairo, struct swaybar_output *output, double *x) {
} }
} // else display on all } // else display on all
if ((int) output->height*output->scale <= 2*config->tray_padding) { if ((int)(output->height * output->scale) <= 2 * config->tray_padding) {
return 2*config->tray_padding + 1; return (2 * config->tray_padding + 1) / output->scale;
} }
uint32_t max_height = 0; uint32_t max_height = 0;

View file

@ -1,4 +1,6 @@
#define _POSIX_C_SOURCE 200809L #define _POSIX_C_SOURCE 200809L
#include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -480,12 +482,20 @@ int main(int argc, char **argv) {
char *resp = ipc_single_command(socketfd, type, command, &len); char *resp = ipc_single_command(socketfd, type, command, &len);
// pretty print the json // pretty print the json
json_object *obj = json_tokener_parse(resp); json_tokener *tok = json_tokener_new_ex(JSON_MAX_DEPTH);
if (obj == NULL) { 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) { if (!quiet) {
fprintf(stderr, "ERROR: Could not parse json response from ipc. " sway_log(SWAY_ERROR, "failed to parse payload as json: %s",
"This is a bug in sway."); json_tokener_error_desc(err));
printf("%s\n", resp);
} }
ret = 1; ret = 1;
} else { } else {
@ -517,13 +527,22 @@ int main(int argc, char **argv) {
break; break;
} }
json_object *obj = json_tokener_parse(reply->payload); json_tokener *tok = json_tokener_new_ex(JSON_MAX_DEPTH);
if (obj == NULL) { if (tok == NULL) {
if (!quiet) { if (quiet) {
fprintf(stderr, "ERROR: Could not parse json response from" exit(EXIT_FAILURE);
" ipc. This is a bug in sway.");
ret = 1;
} }
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; break;
} else if (quiet) { } else if (quiet) {
json_object_put(obj); json_object_put(obj);

View file

@ -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 = { static const struct wl_output_listener output_listener = {
.geometry = nop, .geometry = nop,
.mode = nop, .mode = nop,
.done = nop, .done = nop,
.scale = output_scale, .scale = output_scale,
}; .name = output_name,
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,
.description = nop, .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) { } else if (strcmp(interface, wl_shm_interface.name) == 0) {
swaynag->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1); swaynag->shm = wl_registry_bind(registry, name, &wl_shm_interface, 1);
} else if (strcmp(interface, wl_output_interface.name) == 0) { } else if (strcmp(interface, wl_output_interface.name) == 0) {
if (!swaynag->output && swaynag->xdg_output_manager) { if (!swaynag->output) {
swaynag->querying_outputs++;
struct swaynag_output *output = struct swaynag_output *output =
calloc(1, sizeof(struct swaynag_output)); calloc(1, sizeof(struct swaynag_output));
output->wl_output = wl_registry_bind(registry, name, output->wl_output = wl_registry_bind(registry, name,
&wl_output_interface, 3); &wl_output_interface, 4);
output->wl_name = name; output->wl_name = name;
output->scale = 1; output->scale = 1;
output->swaynag = swaynag; output->swaynag = swaynag;
wl_list_insert(&swaynag->outputs, &output->link); wl_list_insert(&swaynag->outputs, &output->link);
wl_output_add_listener(output->wl_output, wl_output_add_listener(output->wl_output,
&output_listener, 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) { } else if (strcmp(interface, zwlr_layer_shell_v1_interface.name) == 0) {
swaynag->layer_shell = wl_registry_bind( swaynag->layer_shell = wl_registry_bind(
registry, name, &zwlr_layer_shell_v1_interface, 1); 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); assert(swaynag->compositor && swaynag->layer_shell && swaynag->shm);
while (swaynag->querying_outputs > 0) { // Second roundtrip to get wl_output properties
if (wl_display_roundtrip(swaynag->display) < 0) { if (wl_display_roundtrip(swaynag->display) < 0) {
sway_log(SWAY_ERROR, "Error during outputs init."); sway_log(SWAY_ERROR, "Error during outputs init.");
swaynag_destroy(swaynag); swaynag_destroy(swaynag);
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
}
} }
if (!swaynag->output && swaynag->type->output) { if (!swaynag->output && swaynag->type->output) {