mirror of
https://github.com/swaywm/sway.git
synced 2025-04-06 12:27:44 +03:00
Compare commits
143 commits
Author | SHA1 | Date | |
---|---|---|---|
|
a25645a5a6 | ||
|
ab455bbada | ||
|
c2d6aff64c | ||
|
4b185a0fe0 | ||
|
d148560f50 | ||
|
30434b2beb | ||
|
3a49409dae | ||
|
2f5b3c0999 | ||
|
61cc08cf3c | ||
|
8238e5242b | ||
|
5d7b9a8320 | ||
|
9dcccf784b | ||
|
048e304b8a | ||
|
e3d9cc2aa5 | ||
|
962e1e70a6 | ||
|
8a60f30423 | ||
|
7fab75a7a6 | ||
|
0da0d37f3d | ||
|
38005bd854 | ||
|
10e50e6bf9 | ||
|
c1031d8465 | ||
|
4852087e61 | ||
|
851b8c6fb6 | ||
|
d093c2e358 | ||
|
3ff60987f3 | ||
|
8acb0482da | ||
|
30c858423d | ||
|
0b08dce08c | ||
|
f177d05441 | ||
|
3ab1f0ca3d | ||
|
60f06fc4f1 | ||
|
cff16d32f9 | ||
|
e3f0ba4cd9 | ||
|
3629a832e5 | ||
|
a6c0441ee0 | ||
|
c7c0a5a1b3 | ||
|
a1838c5522 | ||
|
0c60d1581f | ||
|
c55dff95bc | ||
|
801bc76ce3 | ||
|
f293418d9d | ||
|
4eb86fce07 | ||
|
1d783794b5 | ||
|
4faf0f9098 | ||
|
bbadf9b8b1 | ||
|
e2409aa496 | ||
|
5312376077 | ||
|
fec3da7d58 | ||
|
a2c73c9b8b | ||
|
6111297d91 | ||
|
96db66abf0 | ||
|
fdc4318ac6 | ||
|
463c4c9369 | ||
|
f23d100747 | ||
|
03483ff370 | ||
|
62fd8c4d01 | ||
|
78fa4e9856 | ||
|
4cfcb3643b | ||
|
d417a8fcd0 | ||
|
f38719f575 | ||
|
1e53007bc3 | ||
|
e7c972b04a | ||
|
839434abc0 | ||
|
015e357fce | ||
|
a63027245a | ||
|
17ecb9eb1d | ||
|
af0d4a048a | ||
|
7e0c0dda42 | ||
|
7d93652105 | ||
|
35d8adefc4 | ||
|
8363699f14 | ||
|
ce6b2db0f2 | ||
|
db76fefd0c | ||
|
dd063a0ef7 | ||
|
17e2e52c6d | ||
|
7f1cd0b73b | ||
|
f855b0898b | ||
|
c90cb37b2a | ||
|
9a9be01ad4 | ||
|
a2757e5f16 | ||
|
a0b3606f17 | ||
|
00e9a94152 | ||
|
63345977e2 | ||
|
cdff4f7c74 | ||
|
b73f54a966 | ||
|
b6da218974 | ||
|
861dde100a | ||
|
e9dd218231 | ||
|
74e507962e | ||
|
023f6b0a50 | ||
|
1537c9dae5 | ||
|
48069097ea | ||
|
266cd4515a | ||
|
e940acd374 | ||
|
9765c29be1 | ||
|
034d02f8a5 | ||
|
785a459a55 | ||
|
f957c7e658 | ||
|
d7a76d381b | ||
|
29b3f00e6f | ||
|
0496477f92 | ||
|
a0c0349934 | ||
|
fb5eadc363 | ||
|
c5ba7f23a5 | ||
|
f4a6b0395f | ||
|
14bff7b451 | ||
|
4f9ce4675c | ||
|
fc6b8d6af2 | ||
|
4fe054c6db | ||
|
cfb292cca7 | ||
|
af28ac04a4 | ||
|
6045ad9a02 | ||
|
b83e5aaa54 | ||
|
be840f730e | ||
|
980a4e0211 | ||
|
f2b2a81149 | ||
|
77b9ddabe2 | ||
|
f00f964abf | ||
|
7288f77bbe | ||
|
f9c0f043e5 | ||
|
ae7c1b139a | ||
|
c30c451907 | ||
|
c3279944fb | ||
|
5a3621460f | ||
|
6576b99c24 | ||
|
b44015578a | ||
|
9ba1beee58 | ||
|
f344e9d5a5 | ||
|
951a22c244 | ||
|
32e5e5232d | ||
|
3e956b9229 | ||
|
05e895c463 | ||
|
9a1c411abd | ||
|
b881c2e84c | ||
|
6e4ccb99c3 | ||
|
9bb45a4037 | ||
|
7e74a49142 | ||
|
4d4c88f0a7 | ||
|
3f327b3db0 | ||
|
a3a9ec1211 | ||
|
50073dc579 | ||
|
fc2796aee8 | ||
|
274a5fcb73 |
93 changed files with 1785 additions and 1132 deletions
|
@ -27,7 +27,7 @@ packages:
|
||||||
- x11/libX11
|
- x11/libX11
|
||||||
- x11/pixman
|
- x11/pixman
|
||||||
- x11/xcb-util-wm
|
- x11/xcb-util-wm
|
||||||
- x11-servers/xwayland-devel
|
- x11-servers/xwayland
|
||||||
- misc/hwdata
|
- misc/hwdata
|
||||||
sources:
|
sources:
|
||||||
- https://github.com/swaywm/sway
|
- https://github.com/swaywm/sway
|
||||||
|
|
11
README.cs.md
11
README.cs.md
|
@ -1,7 +1,5 @@
|
||||||
# sway
|
# sway
|
||||||
|
|
||||||
[English][en] - **[Česky][cs]** - [Deutsch][de] - [Dansk][dk] - [Español][es] - [Français][fr] - [Svenska][sv] - [Ελληνικά][gr] - [हिन्दी][hi] - [Magyar][hu] - [فارسی][ir] - [Italiano][it] - [日本語][ja] - [한국어][ko] - [Nederlands][nl] - [Polski][pl] - [Português][pt] - [Română][ro] - [Русский][ru] - [Türkçe][tr] - [Українська][uk] - [中文-简体][zh-CN] - [中文-繁體][zh-TW]
|
|
||||||
|
|
||||||
sway je s [i3] kompatibilní [Wayland] kompozitor. Přečtěte si [FAQ]. Připojte se na
|
sway je s [i3] kompatibilní [Wayland] kompozitor. Přečtěte si [FAQ]. Připojte se na
|
||||||
[IRC kanál][IRC channel] \(#sway na irc.libera.chat).
|
[IRC kanál][IRC channel] \(#sway na irc.libera.chat).
|
||||||
|
|
||||||
|
@ -32,10 +30,11 @@ Nainstalujte závislosti:
|
||||||
* pango
|
* pango
|
||||||
* cairo
|
* cairo
|
||||||
* gdk-pixbuf2 (volitelné: oznamovací oblast)
|
* gdk-pixbuf2 (volitelné: oznamovací oblast)
|
||||||
|
* [swaybg] (volitelné: tapeta)
|
||||||
* [scdoc] (volitelné: manuálové stránky) \*
|
* [scdoc] (volitelné: manuálové stránky) \*
|
||||||
* git (volitelné: informace o verzi) \*
|
* git (volitelné: informace o verzi) \*
|
||||||
|
|
||||||
_\* Závislost pouze pro sestavení_
|
_\* Závislost pouze pro kompilaci_
|
||||||
|
|
||||||
Spusťte tyto příkazy:
|
Spusťte tyto příkazy:
|
||||||
|
|
||||||
|
@ -56,12 +55,13 @@ Spusťte `sway` z TTY. Některé správce zobrazení mohou fungovat, ale nejsou
|
||||||
podporovány sway (je známo, že gdm funguje docela dobře).
|
podporovány sway (je známo, že gdm funguje docela dobře).
|
||||||
|
|
||||||
[en]: https://github.com/swaywm/sway#readme
|
[en]: https://github.com/swaywm/sway#readme
|
||||||
|
[ar]: README.ar.md
|
||||||
[cs]: README.cs.md
|
[cs]: README.cs.md
|
||||||
[de]: README.de.md
|
[de]: README.de.md
|
||||||
[dk]: README.dk.md
|
[dk]: README.dk.md
|
||||||
[es]: README.es.md
|
[es]: README.es.md
|
||||||
[fr]: README.fr.md
|
[fr]: README.fr.md
|
||||||
[sv]: README.sv.md
|
[ge]: README.ge.md
|
||||||
[gr]: README.gr.md
|
[gr]: README.gr.md
|
||||||
[hi]: README.hi.md
|
[hi]: README.hi.md
|
||||||
[hu]: README.hu.md
|
[hu]: README.hu.md
|
||||||
|
@ -70,10 +70,12 @@ podporovány sway (je známo, že gdm funguje docela dobře).
|
||||||
[ja]: README.ja.md
|
[ja]: README.ja.md
|
||||||
[ko]: README.ko.md
|
[ko]: README.ko.md
|
||||||
[nl]: README.nl.md
|
[nl]: README.nl.md
|
||||||
|
[no]: README.no.md
|
||||||
[pl]: README.pl.md
|
[pl]: README.pl.md
|
||||||
[pt]: README.pt.md
|
[pt]: README.pt.md
|
||||||
[ro]: README.ro.md
|
[ro]: README.ro.md
|
||||||
[ru]: README.ru.md
|
[ru]: README.ru.md
|
||||||
|
[sv]: README.sv.md
|
||||||
[tr]: README.tr.md
|
[tr]: README.tr.md
|
||||||
[uk]: README.uk.md
|
[uk]: README.uk.md
|
||||||
[zh-CN]: README.zh-CN.md
|
[zh-CN]: README.zh-CN.md
|
||||||
|
@ -86,4 +88,5 @@ podporovány sway (je známo, že gdm funguje docela dobře).
|
||||||
[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://gitlab.freedesktop.org/wlroots/wlroots
|
[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
|
||||||
|
[swaybg]: https://github.com/swaywm/swaybg/
|
||||||
[scdoc]: https://git.sr.ht/~sircmpwn/scdoc
|
[scdoc]: https://git.sr.ht/~sircmpwn/scdoc
|
||||||
|
|
14
README.hu.md
14
README.hu.md
|
@ -1,10 +1,10 @@
|
||||||
# sway
|
# sway
|
||||||
|
|
||||||
A Sway egy [i3]-kompatibilis [Wayland] kompozitor. Olvasd el a [Gyarkan Ismételt Kérdéseket][FAQ]. Csatlakozz az [IRC csatornához][IRC channel] \(`#sway` az `irc.libera.chat`-en).
|
A Sway egy [i3]-kompatibilis [Wayland]-kompozitor. Olvasd el a [Gyarkan Ismételt Kérdéseket][FAQ]. Csatlakozz az [IRC-csatornához][IRC channel] \(`#sway` az `irc.libera.chat`-en).
|
||||||
|
|
||||||
## Csomag aláírások
|
## Csomagaláírások
|
||||||
|
|
||||||
A kiadott csomagok az [E88F5E48] kulccsal vannak aláírva és [GitHub-on][GitHub releases] publikálva.
|
A kiadott csomagok az [E88F5E48] kulccsal vannak aláírva, és [GitHubon][GitHub releases] publikálva.
|
||||||
|
|
||||||
## Telepítés
|
## Telepítés
|
||||||
|
|
||||||
|
@ -13,12 +13,12 @@ A kiadott csomagok az [E88F5E48] kulccsal vannak aláírva és [GitHub-on][GitHu
|
||||||
A Sway sok disztribúció csomagkezelőjéből elérhető, próbáld meg a "sway"
|
A Sway sok disztribúció csomagkezelőjéből elérhető, próbáld meg a "sway"
|
||||||
csomagot telepíteni az általad használt eszközzel.
|
csomagot telepíteni az általad használt eszközzel.
|
||||||
|
|
||||||
Ha szeretnél csomagot készíteni a saját disztribúciódhoz, ugorj be az IRC
|
Ha szeretnél csomagot készíteni a saját disztribúciódhoz, ugorj be az IRC-
|
||||||
csatornára, vagy küldj levelet a sir@cmpwn.com címre tanácsokért.
|
csatornára, vagy küldj levelet a sir@cmpwn.com címre tanácsokért.
|
||||||
|
|
||||||
### Fordítás forráskódból
|
### Fordítás forráskódból
|
||||||
|
|
||||||
Olvasd el [ezt a wiki oldalt][Development setup], ha szeretnéd tesztelési vagy
|
Olvasd el [ezt a wikioldalt][Development setup], ha szeretnéd tesztelési vagy
|
||||||
fejlesztési célokból lefordítani az aktuális (HEAD) állapotát a `sway`-nek és a
|
fejlesztési célokból lefordítani az aktuális (HEAD) állapotát a `sway`-nek és a
|
||||||
`wlroots`-nak.
|
`wlroots`-nak.
|
||||||
|
|
||||||
|
@ -46,7 +46,7 @@ Futtasd ezeket a parancsokat:
|
||||||
|
|
||||||
## Konfiguráció
|
## Konfiguráció
|
||||||
|
|
||||||
Ha előzőleg i3-mat használtál, akkor átmásolhatod az i3 beállításaidat a
|
Ha előzőleg i3-at használtál, akkor átmásolhatod az i3-beállításaidat a
|
||||||
`~/.config/sway/config` file-ba és ugyanúgy működni fognak. Egyéb esetben másold
|
`~/.config/sway/config` file-ba és ugyanúgy működni fognak. Egyéb esetben másold
|
||||||
le kiindulási alapnak a mintát, ami általában az `etc/sway/config` elérési
|
le kiindulási alapnak a mintát, ami általában az `etc/sway/config` elérési
|
||||||
útvonalon található.
|
útvonalon található.
|
||||||
|
@ -55,7 +55,7 @@ kapcsolatban.
|
||||||
|
|
||||||
## Futtatás
|
## Futtatás
|
||||||
|
|
||||||
Futtasd a `sway` parancsot egy TTY felületről. Néhány bejelentkezéskezelő
|
Futtasd a `sway` parancsot egy TTY-felületről. Néhány bejelentkezéskezelő
|
||||||
(display manager) működhet, de alapvetően nem támogatottak a sway által. (A
|
(display manager) működhet, de alapvetően nem támogatottak a sway által. (A
|
||||||
gdm-ről ismeretes, hogy egész jól működik.)
|
gdm-ről ismeretes, hogy egész jól működik.)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
# sway
|
# sway
|
||||||
|
|
||||||
[English][en] - [Deutsch][de] - [Dansk][dk] - [Español][es] - [Français][fr] - **[Svenska][sv]** - [Ελληνικά][gr] - [Magyar][hu] - [فارسی][ir] - [Italiano][it] - [日本語][ja] - [한국어][ko] - [Nederlands][nl] - [Polski][pl] - [Português][pt] - [Română][ro] - [Русский][ru] - [Türkçe][tr] - [Українська][uk] - [中文-简体][zh-CN] - [中文-繁體][zh-TW]
|
|
||||||
|
|
||||||
sway är en [i3]-kompatibel [Wayland] compositor. Läs våran [FAQ]-sida. Gå med i vår
|
sway är en [i3]-kompatibel [Wayland] compositor. Läs våran [FAQ]-sida. Gå med i vår
|
||||||
[IRC-kanal] \(#sway på irc.libera.chat).
|
[IRC-kanal] \(#sway på irc.libera.chat).
|
||||||
|
|
||||||
|
|
|
@ -360,3 +360,7 @@ char *format_str(const char *fmt, ...) {
|
||||||
va_end(args);
|
va_end(args);
|
||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool has_prefix(const char *str, const char *prefix) {
|
||||||
|
return strncmp(str, prefix, strlen(prefix)) == 0;
|
||||||
|
}
|
||||||
|
|
17
config.in
17
config.in
|
@ -16,9 +16,7 @@ set $right l
|
||||||
# Your preferred terminal emulator
|
# Your preferred terminal emulator
|
||||||
set $term foot
|
set $term foot
|
||||||
# Your preferred application launcher
|
# Your preferred application launcher
|
||||||
# Note: pass the final command to swaymsg so that the resulting window can be opened
|
set $menu wmenu-run
|
||||||
# on the original workspace that the command was run on.
|
|
||||||
set $menu dmenu_path | wmenu | xargs swaymsg exec --
|
|
||||||
|
|
||||||
### Output configuration
|
### Output configuration
|
||||||
#
|
#
|
||||||
|
@ -195,6 +193,19 @@ mode "resize" {
|
||||||
bindsym Escape mode "default"
|
bindsym Escape mode "default"
|
||||||
}
|
}
|
||||||
bindsym $mod+r mode "resize"
|
bindsym $mod+r mode "resize"
|
||||||
|
#
|
||||||
|
# Utilities:
|
||||||
|
#
|
||||||
|
# Special keys to adjust volume via PulseAudio
|
||||||
|
bindsym --locked XF86AudioMute exec pactl set-sink-mute \@DEFAULT_SINK@ toggle
|
||||||
|
bindsym --locked XF86AudioLowerVolume exec pactl set-sink-volume \@DEFAULT_SINK@ -5%
|
||||||
|
bindsym --locked XF86AudioRaiseVolume exec pactl set-sink-volume \@DEFAULT_SINK@ +5%
|
||||||
|
bindsym --locked XF86AudioMicMute exec pactl set-source-mute \@DEFAULT_SOURCE@ toggle
|
||||||
|
# Special keys to adjust brightness via brightnessctl
|
||||||
|
bindsym --locked XF86MonBrightnessDown exec brightnessctl set 5%-
|
||||||
|
bindsym --locked XF86MonBrightnessUp exec brightnessctl set 5%+
|
||||||
|
# Special key to take a screenshot with grim
|
||||||
|
bindsym Print exec grim
|
||||||
|
|
||||||
#
|
#
|
||||||
# Status Bar:
|
# Status Bar:
|
||||||
|
|
|
@ -40,4 +40,6 @@ bool expand_path(char **path);
|
||||||
char *vformat_str(const char *fmt, va_list args) _SWAY_ATTRIB_PRINTF(1, 0);
|
char *vformat_str(const char *fmt, va_list args) _SWAY_ATTRIB_PRINTF(1, 0);
|
||||||
char *format_str(const char *fmt, ...) _SWAY_ATTRIB_PRINTF(1, 2);
|
char *format_str(const char *fmt, ...) _SWAY_ATTRIB_PRINTF(1, 2);
|
||||||
|
|
||||||
|
bool has_prefix(const char *str, const char *prefix);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -104,6 +104,7 @@ struct sway_container *container_find_resize_parent(struct sway_container *con,
|
||||||
sway_cmd cmd_exec_validate;
|
sway_cmd cmd_exec_validate;
|
||||||
sway_cmd cmd_exec_process;
|
sway_cmd cmd_exec_process;
|
||||||
|
|
||||||
|
sway_cmd cmd_allow_tearing;
|
||||||
sway_cmd cmd_assign;
|
sway_cmd cmd_assign;
|
||||||
sway_cmd cmd_bar;
|
sway_cmd cmd_bar;
|
||||||
sway_cmd cmd_bindcode;
|
sway_cmd cmd_bindcode;
|
||||||
|
@ -283,6 +284,7 @@ sway_cmd input_cmd_xkb_switch_layout;
|
||||||
sway_cmd input_cmd_xkb_variant;
|
sway_cmd input_cmd_xkb_variant;
|
||||||
|
|
||||||
sway_cmd output_cmd_adaptive_sync;
|
sway_cmd output_cmd_adaptive_sync;
|
||||||
|
sway_cmd output_cmd_allow_tearing;
|
||||||
sway_cmd output_cmd_background;
|
sway_cmd output_cmd_background;
|
||||||
sway_cmd output_cmd_color_profile;
|
sway_cmd output_cmd_color_profile;
|
||||||
sway_cmd output_cmd_disable;
|
sway_cmd output_cmd_disable;
|
||||||
|
|
|
@ -262,6 +262,7 @@ enum scale_filter_mode {
|
||||||
|
|
||||||
enum render_bit_depth {
|
enum render_bit_depth {
|
||||||
RENDER_BIT_DEPTH_DEFAULT, // the default is currently 8
|
RENDER_BIT_DEPTH_DEFAULT, // the default is currently 8
|
||||||
|
RENDER_BIT_DEPTH_6,
|
||||||
RENDER_BIT_DEPTH_8,
|
RENDER_BIT_DEPTH_8,
|
||||||
RENDER_BIT_DEPTH_10,
|
RENDER_BIT_DEPTH_10,
|
||||||
};
|
};
|
||||||
|
@ -289,20 +290,13 @@ struct output_config {
|
||||||
enum render_bit_depth render_bit_depth;
|
enum render_bit_depth render_bit_depth;
|
||||||
bool set_color_transform;
|
bool set_color_transform;
|
||||||
struct wlr_color_transform *color_transform;
|
struct wlr_color_transform *color_transform;
|
||||||
|
int allow_tearing;
|
||||||
|
|
||||||
char *background;
|
char *background;
|
||||||
char *background_option;
|
char *background_option;
|
||||||
char *background_fallback;
|
char *background_fallback;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* An output config pre-matched to an output
|
|
||||||
*/
|
|
||||||
struct matched_output_config {
|
|
||||||
struct sway_output *output;
|
|
||||||
struct output_config *config;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stores size of gaps for each side
|
* Stores size of gaps for each side
|
||||||
*/
|
*/
|
||||||
|
@ -692,13 +686,10 @@ const char *sway_output_scale_filter_to_string(enum scale_filter_mode scale_filt
|
||||||
|
|
||||||
struct output_config *new_output_config(const char *name);
|
struct output_config *new_output_config(const char *name);
|
||||||
|
|
||||||
bool apply_output_configs(struct matched_output_config *configs,
|
bool apply_output_configs(struct output_config **ocs, size_t ocs_len,
|
||||||
size_t configs_len, bool test_only, bool degrade_to_off);
|
bool test_only, bool degrade_to_off);
|
||||||
|
|
||||||
void apply_all_output_configs(void);
|
void apply_stored_output_configs(void);
|
||||||
|
|
||||||
void sort_output_configs_by_priority(struct matched_output_config *configs,
|
|
||||||
size_t configs_len);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* store_output_config stores a new output config. An output may be matched by
|
* store_output_config stores a new output config. An output may be matched by
|
||||||
|
@ -713,6 +704,10 @@ struct output_config *find_output_config(struct sway_output *output);
|
||||||
|
|
||||||
void free_output_config(struct output_config *oc);
|
void free_output_config(struct output_config *oc);
|
||||||
|
|
||||||
|
void request_modeset(void);
|
||||||
|
void force_modeset(void);
|
||||||
|
bool modeset_is_pending(void);
|
||||||
|
|
||||||
bool spawn_swaybg(void);
|
bool spawn_swaybg(void);
|
||||||
|
|
||||||
int workspace_output_cmp_workspace(const void *a, const void *b);
|
int workspace_output_cmp_workspace(const void *a, const void *b);
|
||||||
|
|
|
@ -53,6 +53,9 @@ struct criteria {
|
||||||
char urgent; // 'l' for latest or 'o' for oldest
|
char urgent; // 'l' for latest or 'o' for oldest
|
||||||
struct pattern *workspace;
|
struct pattern *workspace;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
struct pattern *sandbox_engine;
|
||||||
|
struct pattern *sandbox_app_id;
|
||||||
|
struct pattern *sandbox_instance_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool criteria_is_empty(struct criteria *criteria);
|
bool criteria_is_empty(struct criteria *criteria);
|
||||||
|
|
|
@ -9,11 +9,14 @@ struct sway_input_popup {
|
||||||
struct wlr_scene_tree *scene_tree;
|
struct wlr_scene_tree *scene_tree;
|
||||||
struct sway_popup_desc desc;
|
struct sway_popup_desc desc;
|
||||||
struct wlr_input_popup_surface_v2 *popup_surface;
|
struct wlr_input_popup_surface_v2 *popup_surface;
|
||||||
|
struct wlr_output *fixed_output;
|
||||||
|
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
|
|
||||||
struct wl_listener popup_destroy;
|
struct wl_listener popup_destroy;
|
||||||
struct wl_listener popup_surface_commit;
|
struct wl_listener popup_surface_commit;
|
||||||
|
struct wl_listener popup_surface_map;
|
||||||
|
struct wl_listener popup_surface_unmap;
|
||||||
|
|
||||||
struct wl_listener focused_surface_unmap;
|
struct wl_listener focused_surface_unmap;
|
||||||
};
|
};
|
||||||
|
|
6
include/sway/lock.h
Normal file
6
include/sway/lock.h
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef _SWAY_LOCK_H
|
||||||
|
#define _SWAY_LOCK_H
|
||||||
|
|
||||||
|
void arrange_locks(void);
|
||||||
|
|
||||||
|
#endif
|
|
@ -57,7 +57,6 @@ struct sway_output {
|
||||||
|
|
||||||
struct wl_listener layout_destroy;
|
struct wl_listener layout_destroy;
|
||||||
struct wl_listener destroy;
|
struct wl_listener destroy;
|
||||||
struct wl_listener commit;
|
|
||||||
struct wl_listener present;
|
struct wl_listener present;
|
||||||
struct wl_listener frame;
|
struct wl_listener frame;
|
||||||
struct wl_listener request_state;
|
struct wl_listener request_state;
|
||||||
|
@ -72,7 +71,7 @@ struct sway_output {
|
||||||
uint32_t refresh_nsec;
|
uint32_t refresh_nsec;
|
||||||
int max_render_time; // In milliseconds
|
int max_render_time; // In milliseconds
|
||||||
struct wl_event_source *repaint_timer;
|
struct wl_event_source *repaint_timer;
|
||||||
bool gamma_lut_changed;
|
bool allow_tearing;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sway_output_non_desktop {
|
struct sway_output_non_desktop {
|
||||||
|
@ -92,6 +91,9 @@ struct sway_output *output_from_wlr_output(struct wlr_output *output);
|
||||||
struct sway_output *output_get_in_direction(struct sway_output *reference,
|
struct sway_output *output_get_in_direction(struct sway_output *reference,
|
||||||
enum wlr_direction direction);
|
enum wlr_direction direction);
|
||||||
|
|
||||||
|
void output_configure_scene(struct sway_output *output,
|
||||||
|
struct wlr_scene_node *node, float opacity);
|
||||||
|
|
||||||
void output_add_workspace(struct sway_output *output,
|
void output_add_workspace(struct sway_output *output,
|
||||||
struct sway_workspace *workspace);
|
struct sway_workspace *workspace);
|
||||||
|
|
||||||
|
@ -135,10 +137,6 @@ enum sway_container_layout output_get_default_layout(
|
||||||
|
|
||||||
enum wlr_direction opposite_direction(enum wlr_direction d);
|
enum wlr_direction opposite_direction(enum wlr_direction d);
|
||||||
|
|
||||||
void handle_output_layout_change(struct wl_listener *listener, void *data);
|
|
||||||
|
|
||||||
void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data);
|
|
||||||
|
|
||||||
void handle_output_manager_apply(struct wl_listener *listener, void *data);
|
void handle_output_manager_apply(struct wl_listener *listener, void *data);
|
||||||
|
|
||||||
void handle_output_manager_test(struct wl_listener *listener, void *data);
|
void handle_output_manager_test(struct wl_listener *listener, void *data);
|
||||||
|
@ -148,4 +146,6 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener,
|
||||||
|
|
||||||
struct sway_output_non_desktop *output_non_desktop_create(struct wlr_output *wlr_output);
|
struct sway_output_non_desktop *output_non_desktop_create(struct wlr_output *wlr_output);
|
||||||
|
|
||||||
|
void update_output_manager_config(struct sway_server *server);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -45,7 +45,6 @@ struct sway_server {
|
||||||
struct sway_input_manager *input;
|
struct sway_input_manager *input;
|
||||||
|
|
||||||
struct wl_listener new_output;
|
struct wl_listener new_output;
|
||||||
struct wl_listener output_layout_change;
|
|
||||||
struct wl_listener renderer_lost;
|
struct wl_listener renderer_lost;
|
||||||
|
|
||||||
struct wlr_idle_notifier_v1 *idle_notifier_v1;
|
struct wlr_idle_notifier_v1 *idle_notifier_v1;
|
||||||
|
@ -105,8 +104,10 @@ struct sway_server {
|
||||||
struct wlr_ext_foreign_toplevel_list_v1 *foreign_toplevel_list;
|
struct wlr_ext_foreign_toplevel_list_v1 *foreign_toplevel_list;
|
||||||
struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager;
|
struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager;
|
||||||
struct wlr_content_type_manager_v1 *content_type_manager_v1;
|
struct wlr_content_type_manager_v1 *content_type_manager_v1;
|
||||||
struct wlr_data_control_manager_v1 *data_control_manager_v1;
|
struct wlr_data_control_manager_v1 *wlr_data_control_manager_v1;
|
||||||
|
struct wlr_ext_data_control_manager_v1 *ext_data_control_manager_v1;
|
||||||
struct wlr_screencopy_manager_v1 *screencopy_manager_v1;
|
struct wlr_screencopy_manager_v1 *screencopy_manager_v1;
|
||||||
|
struct wlr_ext_image_copy_capture_manager_v1 *ext_image_copy_capture_manager_v1;
|
||||||
struct wlr_export_dmabuf_manager_v1 *export_dmabuf_manager_v1;
|
struct wlr_export_dmabuf_manager_v1 *export_dmabuf_manager_v1;
|
||||||
struct wlr_security_context_manager_v1 *security_context_manager_v1;
|
struct wlr_security_context_manager_v1 *security_context_manager_v1;
|
||||||
|
|
||||||
|
@ -116,6 +117,10 @@ struct sway_server {
|
||||||
|
|
||||||
struct wl_listener request_set_cursor_shape;
|
struct wl_listener request_set_cursor_shape;
|
||||||
|
|
||||||
|
struct wlr_tearing_control_manager_v1 *tearing_control_v1;
|
||||||
|
struct wl_listener tearing_control_new_object;
|
||||||
|
struct wl_list tearing_controllers; // sway_tearing_controller::link
|
||||||
|
|
||||||
struct wl_list pending_launcher_ctxs; // launcher_ctx::link
|
struct wl_list pending_launcher_ctxs; // launcher_ctx::link
|
||||||
|
|
||||||
// The timeout for transactions, after which a transaction is applied
|
// The timeout for transactions, after which a transaction is applied
|
||||||
|
@ -158,6 +163,7 @@ 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 restore_nofile_limit(void);
|
||||||
|
void restore_signals(void);
|
||||||
|
|
||||||
void handle_new_output(struct wl_listener *listener, void *data);
|
void handle_new_output(struct wl_listener *listener, void *data);
|
||||||
|
|
||||||
|
@ -182,4 +188,6 @@ void xdg_activation_v1_handle_new_token(struct wl_listener *listener,
|
||||||
|
|
||||||
void set_rr_scheduling(void);
|
void set_rr_scheduling(void);
|
||||||
|
|
||||||
|
void handle_new_tearing_hint(struct wl_listener *listener, void *data);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -103,6 +103,8 @@ struct sway_container {
|
||||||
char *formatted_title; // The title displayed in the title bar
|
char *formatted_title; // The title displayed in the title bar
|
||||||
int title_width;
|
int title_width;
|
||||||
|
|
||||||
|
char *title_format;
|
||||||
|
|
||||||
enum sway_container_layout prev_split_layout;
|
enum sway_container_layout prev_split_layout;
|
||||||
|
|
||||||
// Whether stickiness has been enabled on this container. Use
|
// Whether stickiness has been enabled on this container. Use
|
||||||
|
@ -183,6 +185,8 @@ void container_update_title_bar(struct sway_container *container);
|
||||||
|
|
||||||
void container_update_marks(struct sway_container *container);
|
void container_update_marks(struct sway_container *container);
|
||||||
|
|
||||||
|
size_t parse_title_format(struct sway_container *container, char *buffer);
|
||||||
|
|
||||||
size_t container_build_representation(enum sway_container_layout layout,
|
size_t container_build_representation(enum sway_container_layout layout,
|
||||||
list_t *children, char *buffer);
|
list_t *children, char *buffer);
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,6 @@ struct sway_root {
|
||||||
struct sway_node node;
|
struct sway_node node;
|
||||||
struct wlr_output_layout *output_layout;
|
struct wlr_output_layout *output_layout;
|
||||||
|
|
||||||
struct wl_listener output_layout_change;
|
|
||||||
|
|
||||||
// scene node layout:
|
// scene node layout:
|
||||||
// - root
|
// - root
|
||||||
// - staging
|
// - staging
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <wlr/config.h>
|
#include <wlr/config.h>
|
||||||
#include <wlr/types/wlr_compositor.h>
|
#include <wlr/types/wlr_compositor.h>
|
||||||
#include <wlr/types/wlr_scene.h>
|
#include <wlr/types/wlr_scene.h>
|
||||||
|
#include <wlr/types/wlr_tearing_control_v1.h>
|
||||||
#include "sway/config.h"
|
#include "sway/config.h"
|
||||||
#if WLR_HAS_XWAYLAND
|
#if WLR_HAS_XWAYLAND
|
||||||
#include <wlr/xwayland.h>
|
#include <wlr/xwayland.h>
|
||||||
|
@ -34,6 +35,12 @@ enum sway_view_prop {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum sway_view_tearing_mode {
|
||||||
|
TEARING_OVERRIDE_FALSE,
|
||||||
|
TEARING_OVERRIDE_TRUE,
|
||||||
|
TEARING_WINDOW_HINT,
|
||||||
|
};
|
||||||
|
|
||||||
struct sway_view_impl {
|
struct sway_view_impl {
|
||||||
void (*get_constraints)(struct sway_view *view, double *min_width,
|
void (*get_constraints)(struct sway_view *view, double *min_width,
|
||||||
double *max_width, double *min_height, double *max_height);
|
double *max_width, double *min_height, double *max_height);
|
||||||
|
@ -73,8 +80,6 @@ struct sway_view {
|
||||||
// Used when changing a view from tiled to floating.
|
// Used when changing a view from tiled to floating.
|
||||||
int natural_width, natural_height;
|
int natural_width, natural_height;
|
||||||
|
|
||||||
char *title_format;
|
|
||||||
|
|
||||||
bool using_csd;
|
bool using_csd;
|
||||||
|
|
||||||
struct timespec urgent;
|
struct timespec urgent;
|
||||||
|
@ -111,6 +116,9 @@ struct sway_view {
|
||||||
int max_render_time; // In milliseconds
|
int max_render_time; // In milliseconds
|
||||||
|
|
||||||
enum seat_config_shortcuts_inhibit shortcuts_inhibit;
|
enum seat_config_shortcuts_inhibit shortcuts_inhibit;
|
||||||
|
|
||||||
|
enum sway_view_tearing_mode tearing_mode;
|
||||||
|
enum wp_tearing_control_v1_presentation_hint tearing_hint;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sway_xdg_shell_view {
|
struct sway_xdg_shell_view {
|
||||||
|
@ -213,6 +221,12 @@ const char *view_get_window_role(struct sway_view *view);
|
||||||
|
|
||||||
uint32_t view_get_window_type(struct sway_view *view);
|
uint32_t view_get_window_type(struct sway_view *view);
|
||||||
|
|
||||||
|
const char *view_get_sandbox_engine(struct sway_view *view);
|
||||||
|
|
||||||
|
const char *view_get_sandbox_app_id(struct sway_view *view);
|
||||||
|
|
||||||
|
const char *view_get_sandbox_instance_id(struct sway_view *view);
|
||||||
|
|
||||||
const char *view_get_shell(struct sway_view *view);
|
const char *view_get_shell(struct sway_view *view);
|
||||||
|
|
||||||
void view_get_constraints(struct sway_view *view, double *min_width,
|
void view_get_constraints(struct sway_view *view, double *min_width,
|
||||||
|
@ -335,4 +349,6 @@ void view_assign_ctx(struct sway_view *view, struct launcher_ctx *ctx);
|
||||||
|
|
||||||
void view_send_frame_done(struct sway_view *view);
|
void view_send_frame_done(struct sway_view *view);
|
||||||
|
|
||||||
|
bool view_can_tear(struct sway_view *view);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
43
meson.build
43
meson.build
|
@ -3,7 +3,7 @@ project(
|
||||||
'c',
|
'c',
|
||||||
version: '1.10-dev',
|
version: '1.10-dev',
|
||||||
license: 'MIT',
|
license: 'MIT',
|
||||||
meson_version: '>=0.60.0',
|
meson_version: '>=1.3',
|
||||||
default_options: [
|
default_options: [
|
||||||
'c_std=c11',
|
'c_std=c11',
|
||||||
'warning_level=2',
|
'warning_level=2',
|
||||||
|
@ -38,14 +38,14 @@ if is_freebsd
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Execute the wlroots subproject, if any
|
# Execute the wlroots subproject, if any
|
||||||
wlroots_version = ['>=0.18.0', '<0.19.0']
|
wlroots_version = ['>=0.19.0', '<0.20.0']
|
||||||
subproject(
|
subproject(
|
||||||
'wlroots',
|
'wlroots',
|
||||||
default_options: ['examples=false'],
|
default_options: ['examples=false'],
|
||||||
required: false,
|
required: false,
|
||||||
version: wlroots_version,
|
version: wlroots_version,
|
||||||
)
|
)
|
||||||
wlroots = dependency('wlroots-0.18', version: wlroots_version, fallback: 'wlroots')
|
wlroots = dependency('wlroots-0.19', version: wlroots_version, fallback: 'wlroots')
|
||||||
wlroots_features = {
|
wlroots_features = {
|
||||||
'xwayland': false,
|
'xwayland': false,
|
||||||
'libinput_backend': false,
|
'libinput_backend': false,
|
||||||
|
@ -109,11 +109,9 @@ conf_data.set10('HAVE_LIBSYSTEMD', sdbus.found() and sdbus.name() == 'libsystemd
|
||||||
conf_data.set10('HAVE_LIBELOGIND', sdbus.found() and sdbus.name() == 'libelogind')
|
conf_data.set10('HAVE_LIBELOGIND', sdbus.found() and sdbus.name() == 'libelogind')
|
||||||
conf_data.set10('HAVE_BASU', sdbus.found() and sdbus.name() == 'basu')
|
conf_data.set10('HAVE_BASU', sdbus.found() and sdbus.name() == 'basu')
|
||||||
conf_data.set10('HAVE_TRAY', have_tray)
|
conf_data.set10('HAVE_TRAY', have_tray)
|
||||||
conf_data.set10('HAVE_LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM', cc.has_header_symbol(
|
foreach sym : ['LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM', 'LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY']
|
||||||
'libinput.h',
|
conf_data.set10('HAVE_' + sym, cc.has_header_symbol('libinput.h', sym, dependencies: libinput))
|
||||||
'LIBINPUT_CONFIG_ACCEL_PROFILE_CUSTOM',
|
endforeach
|
||||||
dependencies: libinput,
|
|
||||||
))
|
|
||||||
|
|
||||||
scdoc = dependency('scdoc', version: '>=1.9.2', native: true, required: get_option('man-pages'))
|
scdoc = dependency('scdoc', version: '>=1.9.2', native: true, required: get_option('man-pages'))
|
||||||
if scdoc.found()
|
if scdoc.found()
|
||||||
|
@ -160,8 +158,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'], check: false)
|
git_commit = run_command([git, '--git-dir=.git', 'rev-parse', '--short', 'HEAD'], check: false)
|
||||||
git_branch = run_command([git, 'rev-parse', '--abbrev-ref', 'HEAD'], check: false)
|
git_branch = run_command([git, '--git-dir=.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(),
|
||||||
|
@ -172,31 +170,10 @@ if git.found()
|
||||||
endif
|
endif
|
||||||
add_project_arguments('-DSWAY_VERSION=@0@'.format(version), language: 'c')
|
add_project_arguments('-DSWAY_VERSION=@0@'.format(version), language: 'c')
|
||||||
|
|
||||||
# Compute the relative path used by compiler invocations.
|
fs = import('fs')
|
||||||
source_root = meson.current_source_dir().split('/')
|
|
||||||
build_root = meson.global_build_root().split('/')
|
|
||||||
relative_dir_parts = []
|
|
||||||
i = 0
|
|
||||||
in_prefix = true
|
|
||||||
foreach p : build_root
|
|
||||||
if i >= source_root.length() or not in_prefix or p != source_root[i]
|
|
||||||
in_prefix = false
|
|
||||||
relative_dir_parts += '..'
|
|
||||||
endif
|
|
||||||
i += 1
|
|
||||||
endforeach
|
|
||||||
i = 0
|
|
||||||
in_prefix = true
|
|
||||||
foreach p : source_root
|
|
||||||
if i >= build_root.length() or not in_prefix or build_root[i] != p
|
|
||||||
in_prefix = false
|
|
||||||
relative_dir_parts += p
|
|
||||||
endif
|
|
||||||
i += 1
|
|
||||||
endforeach
|
|
||||||
relative_dir = join_paths(relative_dir_parts) + '/'
|
|
||||||
|
|
||||||
# Strip relative path prefixes from the code if possible, otherwise hide them.
|
# Strip relative path prefixes from the code if possible, otherwise hide them.
|
||||||
|
relative_dir = fs.relative_to(meson.current_source_dir(), meson.global_build_root()) + '/'
|
||||||
if cc.has_argument('-fmacro-prefix-map=/prefix/to/hide=')
|
if cc.has_argument('-fmacro-prefix-map=/prefix/to/hide=')
|
||||||
add_project_arguments(
|
add_project_arguments(
|
||||||
'-fmacro-prefix-map=@0@='.format(relative_dir),
|
'-fmacro-prefix-map=@0@='.format(relative_dir),
|
||||||
|
|
|
@ -9,11 +9,15 @@ wayland_scanner = find_program(
|
||||||
protocols = [
|
protocols = [
|
||||||
wl_protocol_dir / 'stable/tablet/tablet-v2.xml',
|
wl_protocol_dir / 'stable/tablet/tablet-v2.xml',
|
||||||
wl_protocol_dir / 'stable/xdg-shell/xdg-shell.xml',
|
wl_protocol_dir / 'stable/xdg-shell/xdg-shell.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/linux-dmabuf/linux-dmabuf-unstable-v1.xml',
|
|
||||||
wl_protocol_dir / 'staging/content-type/content-type-v1.xml',
|
wl_protocol_dir / 'staging/content-type/content-type-v1.xml',
|
||||||
wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml',
|
wl_protocol_dir / 'staging/cursor-shape/cursor-shape-v1.xml',
|
||||||
|
wl_protocol_dir / 'staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml',
|
||||||
|
wl_protocol_dir / 'staging/ext-image-capture-source/ext-image-capture-source-v1.xml',
|
||||||
|
wl_protocol_dir / 'staging/ext-image-copy-capture/ext-image-copy-capture-v1.xml',
|
||||||
|
wl_protocol_dir / 'staging/tearing-control/tearing-control-v1.xml',
|
||||||
|
wl_protocol_dir / 'unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml',
|
||||||
|
wl_protocol_dir / 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml',
|
||||||
|
wl_protocol_dir / 'unstable/xdg-output/xdg-output-unstable-v1.xml',
|
||||||
'wlr-layer-shell-unstable-v1.xml',
|
'wlr-layer-shell-unstable-v1.xml',
|
||||||
'idle.xml',
|
'idle.xml',
|
||||||
'wlr-output-power-management-unstable-v1.xml',
|
'wlr-output-power-management-unstable-v1.xml',
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#!/bin/sh -eu
|
#!/bin/sh -eu
|
||||||
|
|
||||||
prev=$(git describe --tags --abbrev=0)
|
prev=$(git describe --tags --abbrev=0)
|
||||||
next=$(meson rewrite kwargs info project / 2>&1 >/dev/null | jq -r '.kwargs["project#/"].version')
|
next=$(meson rewrite kwargs info project / | jq -r '.kwargs["project#/"].version')
|
||||||
|
|
||||||
case "$next" in
|
case "$next" in
|
||||||
*-dev)
|
*-dev)
|
||||||
|
@ -28,4 +28,5 @@ archive=$prefix.tar.gz
|
||||||
git archive --prefix="$prefix/" -o "$archive" "$next"
|
git archive --prefix="$prefix/" -o "$archive" "$next"
|
||||||
gpg --output "$archive".sig --detach-sig "$archive"
|
gpg --output "$archive".sig --detach-sig "$archive"
|
||||||
|
|
||||||
|
git push --follow-tags
|
||||||
gh release create "sway $next" -t "$next" -n "" -d "$archive" "$archive.sig"
|
gh release create "sway $next" -t "$next" -n "" -d "$archive" "$archive.sig"
|
||||||
|
|
|
@ -3,3 +3,4 @@ Name=Sway
|
||||||
Comment=An i3-compatible Wayland compositor
|
Comment=An i3-compatible Wayland compositor
|
||||||
Exec=sway
|
Exec=sway
|
||||||
Type=Application
|
Type=Application
|
||||||
|
DesktopNames=sway;wlroots
|
||||||
|
|
|
@ -112,6 +112,7 @@ static const struct cmd_handler config_handlers[] = {
|
||||||
|
|
||||||
/* Runtime-only commands. Keep alphabetized */
|
/* Runtime-only commands. Keep alphabetized */
|
||||||
static const struct cmd_handler command_handlers[] = {
|
static const struct cmd_handler command_handlers[] = {
|
||||||
|
{ "allow_tearing", cmd_allow_tearing },
|
||||||
{ "border", cmd_border },
|
{ "border", cmd_border },
|
||||||
{ "create_output", cmd_create_output },
|
{ "create_output", cmd_create_output },
|
||||||
{ "exit", cmd_exit },
|
{ "exit", cmd_exit },
|
||||||
|
|
24
sway/commands/allow_tearing.c
Normal file
24
sway/commands/allow_tearing.c
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
#include <sway/commands.h>
|
||||||
|
#include "sway/config.h"
|
||||||
|
#include "sway/tree/view.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
struct cmd_results *cmd_allow_tearing(int argc, char **argv) {
|
||||||
|
struct cmd_results *error = NULL;
|
||||||
|
if ((error = checkarg(argc, "allow_tearing", EXPECTED_AT_LEAST, 1))) {
|
||||||
|
return error;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sway_container *container = config->handler_context.container;
|
||||||
|
if (!container || !container->view) {
|
||||||
|
return cmd_results_new(CMD_INVALID, "Tearing can only be allowed on views");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wants_tearing = parse_boolean(argv[0], true);
|
||||||
|
|
||||||
|
struct sway_view *view = container->view;
|
||||||
|
view->tearing_mode = wants_tearing ? TEARING_OVERRIDE_TRUE :
|
||||||
|
TEARING_OVERRIDE_FALSE;
|
||||||
|
|
||||||
|
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||||
|
}
|
|
@ -23,7 +23,7 @@ struct cmd_results *cmd_assign(int argc, char **argv) {
|
||||||
|
|
||||||
--argc; ++argv;
|
--argc; ++argv;
|
||||||
|
|
||||||
if (strncmp(*argv, "→", strlen("→")) == 0) {
|
if (has_prefix(*argv, "→")) {
|
||||||
if (argc < 2) {
|
if (argc < 2) {
|
||||||
free(criteria);
|
free(criteria);
|
||||||
return cmd_results_new(CMD_INVALID, "Missing workspace");
|
return cmd_results_new(CMD_INVALID, "Missing workspace");
|
||||||
|
|
|
@ -11,7 +11,7 @@ struct cmd_results *bar_cmd_font(int argc, char **argv) {
|
||||||
char *font = join_args(argv, argc);
|
char *font = join_args(argv, argc);
|
||||||
free(config->current_bar->font);
|
free(config->current_bar->font);
|
||||||
|
|
||||||
if (strncmp(font, "pango:", 6) == 0) {
|
if (has_prefix(font, "pango:")) {
|
||||||
if (config->current_bar->pango_markup == PANGO_MARKUP_DEFAULT) {
|
if (config->current_bar->pango_markup == PANGO_MARKUP_DEFAULT) {
|
||||||
config->current_bar->pango_markup = true;
|
config->current_bar->pango_markup = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -367,8 +367,7 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
|
||||||
}
|
}
|
||||||
} else if (strcmp("--exclude-titlebar", argv[0]) == 0) {
|
} else if (strcmp("--exclude-titlebar", argv[0]) == 0) {
|
||||||
exclude_titlebar = true;
|
exclude_titlebar = true;
|
||||||
} else if (strncmp("--input-device=", argv[0],
|
} else if (has_prefix(argv[0], "--input-device=")) {
|
||||||
strlen("--input-device=")) == 0) {
|
|
||||||
free(binding->input);
|
free(binding->input);
|
||||||
binding->input = strdup(argv[0] + strlen("--input-device="));
|
binding->input = strdup(argv[0] + strlen("--input-device="));
|
||||||
strip_quotes(binding->input);
|
strip_quotes(binding->input);
|
||||||
|
@ -399,7 +398,7 @@ static struct cmd_results *cmd_bindsym_or_bindcode(int argc, char **argv,
|
||||||
list_t *split = split_string(argv[0], "+");
|
list_t *split = split_string(argv[0], "+");
|
||||||
for (int i = 0; i < split->length; ++i) {
|
for (int i = 0; i < split->length; ++i) {
|
||||||
// Check for group
|
// Check for group
|
||||||
if (strncmp(split->items[i], "Group", strlen("Group")) == 0) {
|
if (has_prefix(split->items[i], "Group")) {
|
||||||
if (binding->group != XKB_LAYOUT_INVALID) {
|
if (binding->group != XKB_LAYOUT_INVALID) {
|
||||||
free_sway_binding(binding);
|
free_sway_binding(binding);
|
||||||
list_free_items_and_destroy(split);
|
list_free_items_and_destroy(split);
|
||||||
|
|
|
@ -25,16 +25,6 @@ struct cmd_results *cmd_exec_validate(int argc, char **argv) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void export_xdga_token(struct launcher_ctx *ctx) {
|
|
||||||
const char *token = launcher_ctx_get_token_name(ctx);
|
|
||||||
setenv("XDG_ACTIVATION_TOKEN", token, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void export_startup_id(struct launcher_ctx *ctx) {
|
|
||||||
const char *token = launcher_ctx_get_token_name(ctx);
|
|
||||||
setenv("DESKTOP_STARTUP_ID", token, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct cmd_results *cmd_exec_process(int argc, char **argv) {
|
struct cmd_results *cmd_exec_process(int argc, char **argv) {
|
||||||
struct cmd_results *error = NULL;
|
struct cmd_results *error = NULL;
|
||||||
char *cmd = NULL;
|
char *cmd = NULL;
|
||||||
|
@ -56,67 +46,39 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) {
|
||||||
|
|
||||||
sway_log(SWAY_DEBUG, "Executing %s", cmd);
|
sway_log(SWAY_DEBUG, "Executing %s", cmd);
|
||||||
|
|
||||||
int fd[2];
|
|
||||||
if (pipe(fd) != 0) {
|
|
||||||
sway_log(SWAY_ERROR, "Unable to create pipe for fork");
|
|
||||||
}
|
|
||||||
|
|
||||||
pid_t pid, child;
|
|
||||||
struct launcher_ctx *ctx = launcher_ctx_create_internal();
|
struct launcher_ctx *ctx = launcher_ctx_create_internal();
|
||||||
|
|
||||||
// Fork process
|
// Fork process
|
||||||
if ((pid = fork()) == 0) {
|
pid_t child = fork();
|
||||||
// Fork child process again
|
if (child == 0) {
|
||||||
restore_nofile_limit();
|
restore_nofile_limit();
|
||||||
|
restore_signals();
|
||||||
setsid();
|
setsid();
|
||||||
sigset_t set;
|
|
||||||
sigemptyset(&set);
|
if (ctx) {
|
||||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
const char *token = launcher_ctx_get_token_name(ctx);
|
||||||
signal(SIGPIPE, SIG_DFL);
|
setenv("XDG_ACTIVATION_TOKEN", token, 1);
|
||||||
close(fd[0]);
|
if (!no_startup_id) {
|
||||||
if ((child = fork()) == 0) {
|
setenv("DESKTOP_STARTUP_ID", token, 1);
|
||||||
close(fd[1]);
|
|
||||||
if (ctx) {
|
|
||||||
export_xdga_token(ctx);
|
|
||||||
}
|
}
|
||||||
if (ctx && !no_startup_id) {
|
|
||||||
export_startup_id(ctx);
|
|
||||||
}
|
|
||||||
execlp("sh", "sh", "-c", cmd, (void *)NULL);
|
|
||||||
sway_log_errno(SWAY_ERROR, "execlp failed");
|
|
||||||
_exit(1);
|
|
||||||
}
|
}
|
||||||
ssize_t s = 0;
|
|
||||||
while ((size_t)s < sizeof(pid_t)) {
|
execlp("sh", "sh", "-c", cmd, (void*)NULL);
|
||||||
s += write(fd[1], ((uint8_t *)&child) + s, sizeof(pid_t) - s);
|
sway_log_errno(SWAY_ERROR, "execve failed");
|
||||||
}
|
|
||||||
close(fd[1]);
|
|
||||||
_exit(0); // Close child process
|
_exit(0); // Close child process
|
||||||
} else if (pid < 0) {
|
} else if (child < 0) {
|
||||||
|
launcher_ctx_destroy(ctx);
|
||||||
free(cmd);
|
free(cmd);
|
||||||
close(fd[0]);
|
|
||||||
close(fd[1]);
|
|
||||||
return cmd_results_new(CMD_FAILURE, "fork() failed");
|
return cmd_results_new(CMD_FAILURE, "fork() failed");
|
||||||
}
|
}
|
||||||
free(cmd);
|
|
||||||
close(fd[1]); // close write
|
sway_log(SWAY_DEBUG, "Child process created with pid %d", child);
|
||||||
ssize_t s = 0;
|
if (ctx != NULL) {
|
||||||
while ((size_t)s < sizeof(pid_t)) {
|
sway_log(SWAY_DEBUG, "Recording workspace for process %d", child);
|
||||||
s += read(fd[0], ((uint8_t *)&child) + s, sizeof(pid_t) - s);
|
ctx->pid = child;
|
||||||
}
|
|
||||||
close(fd[0]);
|
|
||||||
// cleanup child process
|
|
||||||
waitpid(pid, NULL, 0);
|
|
||||||
if (child > 0) {
|
|
||||||
sway_log(SWAY_DEBUG, "Child process created with pid %d", child);
|
|
||||||
if (ctx != NULL) {
|
|
||||||
sway_log(SWAY_DEBUG, "Recording workspace for process %d", child);
|
|
||||||
ctx->pid = child;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
launcher_ctx_destroy(ctx);
|
|
||||||
return cmd_results_new(CMD_FAILURE, "Second fork() failed");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(cmd);
|
||||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,9 +13,9 @@ struct cmd_results *cmd_font(int argc, char **argv) {
|
||||||
char *font = join_args(argv, argc);
|
char *font = join_args(argv, argc);
|
||||||
free(config->font);
|
free(config->font);
|
||||||
|
|
||||||
if (strncmp(font, "pango:", 6) == 0) {
|
if (has_prefix(font, "pango:")) {
|
||||||
config->pango_markup = true;
|
config->pango_markup = true;
|
||||||
config->font = strdup(font + 6);
|
config->font = strdup(font + strlen("pango:"));
|
||||||
free(font);
|
free(font);
|
||||||
} else {
|
} else {
|
||||||
config->pango_markup = false;
|
config->pango_markup = false;
|
||||||
|
|
|
@ -215,15 +215,13 @@ struct cmd_results *cmd_gaps(int argc, char **argv) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool config_loading = !config->active || config->reloading;
|
|
||||||
|
|
||||||
if (argc == 2) {
|
if (argc == 2) {
|
||||||
return gaps_set_defaults(argc, argv);
|
return gaps_set_defaults(argc, argv);
|
||||||
}
|
}
|
||||||
if (argc == 4 && !config_loading) {
|
if (argc == 4 && !config->reading) {
|
||||||
return gaps_set_runtime(argc, argv);
|
return gaps_set_runtime(argc, argv);
|
||||||
}
|
}
|
||||||
if (config_loading) {
|
if (config->reading) {
|
||||||
return cmd_results_new(CMD_INVALID, "Expected %s", expected_defaults);
|
return cmd_results_new(CMD_INVALID, "Expected %s", expected_defaults);
|
||||||
}
|
}
|
||||||
return cmd_results_new(CMD_INVALID, "Expected %s or %s",
|
return cmd_results_new(CMD_INVALID, "Expected %s or %s",
|
||||||
|
|
|
@ -121,8 +121,7 @@ static struct cmd_results *cmd_bind_or_unbind_gesture(int argc, char **argv, boo
|
||||||
binding->flags |= BINDING_EXACT;
|
binding->flags |= BINDING_EXACT;
|
||||||
} else if (strcmp("--no-warn", argv[0]) == 0) {
|
} else if (strcmp("--no-warn", argv[0]) == 0) {
|
||||||
warn = false;
|
warn = false;
|
||||||
} else if (strncmp("--input-device=", argv[0],
|
} else if (has_prefix(argv[0], "--input-device=")) {
|
||||||
strlen("--input-device=")) == 0) {
|
|
||||||
free(binding->input);
|
free(binding->input);
|
||||||
binding->input = strdup(argv[0] + strlen("--input-device="));
|
binding->input = strdup(argv[0] + strlen("--input-device="));
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -3,12 +3,12 @@
|
||||||
|
|
||||||
struct cmd_results *cmd_include(int argc, char **argv) {
|
struct cmd_results *cmd_include(int argc, char **argv) {
|
||||||
struct cmd_results *error = NULL;
|
struct cmd_results *error = NULL;
|
||||||
if ((error = checkarg(argc, "include", EXPECTED_EQUAL_TO, 1))) {
|
if ((error = checkarg(argc, "include", EXPECTED_AT_LEAST, 1))) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
|
char *files = join_args(argv, argc);
|
||||||
// We don't care if the included config(s) fails to load.
|
// We don't care if the included config(s) fails to load.
|
||||||
load_include_configs(argv[0], config, &config->swaynag_config_errors);
|
load_include_configs(files, config, &config->swaynag_config_errors);
|
||||||
|
|
||||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,7 +94,7 @@ struct cmd_results *cmd_input(int argc, char **argv) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!config->reloading) {
|
if (!config->reading) {
|
||||||
input_manager_apply_input_config(ic);
|
input_manager_apply_input_config(ic);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -15,6 +15,11 @@ struct cmd_results *input_cmd_drag_lock(int argc, char **argv) {
|
||||||
return cmd_results_new(CMD_FAILURE, "No input device defined.");
|
return cmd_results_new(CMD_FAILURE, "No input device defined.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if HAVE_LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY
|
||||||
|
if (strcmp(argv[0], "enabled_sticky") == 0) {
|
||||||
|
ic->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY;
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
if (parse_boolean(argv[0], true)) {
|
if (parse_boolean(argv[0], true)) {
|
||||||
ic->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED;
|
ic->drag_lock = LIBINPUT_CONFIG_DRAG_LOCK_ENABLED;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -86,7 +86,7 @@ static void toggle_select_send_events_for_device(struct input_config *ic,
|
||||||
static void toggle_send_events(int argc, char **argv) {
|
static void toggle_send_events(int argc, char **argv) {
|
||||||
struct input_config *ic = config->handler_context.input_config;
|
struct input_config *ic = config->handler_context.input_config;
|
||||||
bool wildcard = strcmp(ic->identifier, "*") == 0;
|
bool wildcard = strcmp(ic->identifier, "*") == 0;
|
||||||
const char *type = strncmp(ic->identifier, "type:", strlen("type:")) == 0
|
const char *type = has_prefix(ic->identifier, "type:")
|
||||||
? ic->identifier + strlen("type:") : NULL;
|
? ic->identifier + strlen("type:") : NULL;
|
||||||
struct sway_input_device *device = NULL;
|
struct sway_input_device *device = NULL;
|
||||||
wl_list_for_each(device, &server.input->devices, link) {
|
wl_list_for_each(device, &server.input->devices, link) {
|
||||||
|
@ -146,8 +146,7 @@ struct cmd_results *input_cmd_events(int argc, char **argv) {
|
||||||
|
|
||||||
toggle_send_events(argc - 1, argv + 1);
|
toggle_send_events(argc - 1, argv + 1);
|
||||||
|
|
||||||
if (strcmp(ic->identifier, "*") == 0 ||
|
if (strcmp(ic->identifier, "*") == 0 || has_prefix(ic->identifier, "type:")) {
|
||||||
strncmp(ic->identifier, "type:", strlen("type:")) == 0) {
|
|
||||||
// Update the device input configs and then reset the type/wildcard
|
// Update the device input configs and then reset the type/wildcard
|
||||||
// config send events mode so that is does not override the device
|
// config send events mode so that is does not override the device
|
||||||
// ones. The device ones will be applied when attempting to apply
|
// ones. The device ones will be applied when attempting to apply
|
||||||
|
|
|
@ -95,10 +95,18 @@ struct cmd_results *input_cmd_xkb_switch_layout(int argc, char **argv) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct wlr_keyboard *keyboard =
|
||||||
|
wlr_keyboard_from_input_device(dev->wlr_device);
|
||||||
|
if (keyboard->keymap == NULL && dev->is_virtual) {
|
||||||
|
// The `sway_keyboard_set_layout` function is by default skipped
|
||||||
|
// when configuring virtual keyboards.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
struct xkb_switch_layout_action *action =
|
struct xkb_switch_layout_action *action =
|
||||||
&actions[actions_len++];
|
&actions[actions_len++];
|
||||||
|
action->keyboard = keyboard;
|
||||||
|
|
||||||
action->keyboard = wlr_keyboard_from_input_device(dev->wlr_device);
|
|
||||||
if (relative) {
|
if (relative) {
|
||||||
action->layout = get_layout_relative(action->keyboard, relative);
|
action->layout = get_layout_relative(action->keyboard, relative);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -23,7 +23,7 @@ struct cmd_results *cmd_mark(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool add = false, toggle = false;
|
bool add = false, toggle = false;
|
||||||
while (argc > 0 && strncmp(*argv, "--", 2) == 0) {
|
while (argc > 0 && has_prefix(*argv, "--")) {
|
||||||
if (strcmp(*argv, "--add") == 0) {
|
if (strcmp(*argv, "--add") == 0) {
|
||||||
add = true;
|
add = true;
|
||||||
} else if (strcmp(*argv, "--replace") == 0) {
|
} else if (strcmp(*argv, "--replace") == 0) {
|
||||||
|
|
|
@ -240,7 +240,6 @@ static void container_move_to_workspace(struct sway_container *container,
|
||||||
static void container_move_to_container(struct sway_container *container,
|
static void container_move_to_container(struct sway_container *container,
|
||||||
struct sway_container *destination) {
|
struct sway_container *destination) {
|
||||||
if (container == destination
|
if (container == destination
|
||||||
|| container_has_ancestor(container, destination)
|
|
||||||
|| container_has_ancestor(destination, container)) {
|
|| container_has_ancestor(destination, container)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -510,6 +509,7 @@ static struct cmd_results *cmd_move_container(bool no_auto_back_and_forth,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ws = workspace_create(NULL, ws_name);
|
ws = workspace_create(NULL, ws_name);
|
||||||
|
arrange_workspace(ws);
|
||||||
}
|
}
|
||||||
free(ws_name);
|
free(ws_name);
|
||||||
struct sway_container *dst = seat_get_focus_inactive_tiling(seat, ws);
|
struct sway_container *dst = seat_get_focus_inactive_tiling(seat, ws);
|
||||||
|
|
|
@ -2,7 +2,8 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include "sway/commands.h"
|
#include "sway/commands.h"
|
||||||
#include "sway/tree/view.h"
|
#include "sway/tree/container.h"
|
||||||
|
#include "sway/output.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
|
||||||
struct cmd_results *cmd_opacity(int argc, char **argv) {
|
struct cmd_results *cmd_opacity(int argc, char **argv) {
|
||||||
|
@ -37,6 +38,7 @@ struct cmd_results *cmd_opacity(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
con->alpha = val;
|
con->alpha = val;
|
||||||
|
output_configure_scene(NULL, &con->scene_tree->node, 1);
|
||||||
container_update(con);
|
container_update(con);
|
||||||
|
|
||||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
// must be in order for the bsearch
|
// must be in order for the bsearch
|
||||||
static const struct cmd_handler output_handlers[] = {
|
static const struct cmd_handler output_handlers[] = {
|
||||||
{ "adaptive_sync", output_cmd_adaptive_sync },
|
{ "adaptive_sync", output_cmd_adaptive_sync },
|
||||||
|
{ "allow_tearing", output_cmd_allow_tearing },
|
||||||
{ "background", output_cmd_background },
|
{ "background", output_cmd_background },
|
||||||
{ "bg", output_cmd_background },
|
{ "bg", output_cmd_background },
|
||||||
{ "color_profile", output_cmd_color_profile },
|
{ "color_profile", output_cmd_color_profile },
|
||||||
|
@ -106,17 +107,16 @@ struct cmd_results *cmd_output(int argc, char **argv) {
|
||||||
|
|
||||||
store_output_config(output);
|
store_output_config(output);
|
||||||
|
|
||||||
// If reloading, the output configs will be applied after reading the
|
if (config->reading) {
|
||||||
// entire config and before the deferred commands so that an auto generated
|
// When reading the config file, we wait till the end to do a single
|
||||||
// workspace name is not given to re-enabled outputs.
|
// modeset and swaybg spawn.
|
||||||
if (!config->reloading && !config->validating) {
|
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||||
apply_all_output_configs();
|
}
|
||||||
if (background) {
|
request_modeset();
|
||||||
if (!spawn_swaybg()) {
|
|
||||||
return cmd_results_new(CMD_FAILURE,
|
if (background && !spawn_swaybg()) {
|
||||||
"Failed to apply background configuration");
|
return cmd_results_new(CMD_FAILURE,
|
||||||
}
|
"Failed to apply background configuration");
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
|
#include <strings.h>
|
||||||
#include "sway/commands.h"
|
#include "sway/commands.h"
|
||||||
#include "sway/config.h"
|
#include "sway/config.h"
|
||||||
|
#include "sway/output.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
struct cmd_results *output_cmd_adaptive_sync(int argc, char **argv) {
|
struct cmd_results *output_cmd_adaptive_sync(int argc, char **argv) {
|
||||||
|
@ -10,12 +12,26 @@ struct cmd_results *output_cmd_adaptive_sync(int argc, char **argv) {
|
||||||
return cmd_results_new(CMD_INVALID, "Missing adaptive_sync argument");
|
return cmd_results_new(CMD_INVALID, "Missing adaptive_sync argument");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (parse_boolean(argv[0], true)) {
|
bool current_value = true;
|
||||||
config->handler_context.output_config->adaptive_sync = 1;
|
if (strcasecmp(argv[0], "toggle") == 0) {
|
||||||
} else {
|
const char *oc_name = config->handler_context.output_config->name;
|
||||||
config->handler_context.output_config->adaptive_sync = 0;
|
if (strcmp(oc_name, "*") == 0) {
|
||||||
|
return cmd_results_new(CMD_INVALID,
|
||||||
|
"Cannot apply toggle to all outputs");
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sway_output *sway_output = all_output_by_name_or_id(oc_name);
|
||||||
|
if (!sway_output || !sway_output->wlr_output) {
|
||||||
|
return cmd_results_new(CMD_FAILURE,
|
||||||
|
"Cannot apply toggle to unknown output %s", oc_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
current_value =
|
||||||
|
sway_output->wlr_output->adaptive_sync_status == WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
config->handler_context.output_config->adaptive_sync = parse_boolean(argv[0], current_value);
|
||||||
|
|
||||||
config->handler_context.leftovers.argc = argc - 1;
|
config->handler_context.leftovers.argc = argc - 1;
|
||||||
config->handler_context.leftovers.argv = argv + 1;
|
config->handler_context.leftovers.argv = argv + 1;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
23
sway/commands/output/allow_tearing.c
Normal file
23
sway/commands/output/allow_tearing.c
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
#include "sway/commands.h"
|
||||||
|
#include "sway/config.h"
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
struct cmd_results *output_cmd_allow_tearing(int argc, char **argv) {
|
||||||
|
if (!config->handler_context.output_config) {
|
||||||
|
return cmd_results_new(CMD_FAILURE, "Missing output config");
|
||||||
|
}
|
||||||
|
if (argc == 0) {
|
||||||
|
return cmd_results_new(CMD_INVALID, "Missing allow_tearing argument");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parse_boolean(argv[0],
|
||||||
|
(config->handler_context.output_config->allow_tearing == 1))) {
|
||||||
|
config->handler_context.output_config->allow_tearing = 1;
|
||||||
|
} else {
|
||||||
|
config->handler_context.output_config->allow_tearing = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
config->handler_context.leftovers.argc = argc - 1;
|
||||||
|
config->handler_context.leftovers.argv = argv + 1;
|
||||||
|
return NULL;
|
||||||
|
}
|
|
@ -3,10 +3,8 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
|
||||||
#include "sway/commands.h"
|
#include "sway/commands.h"
|
||||||
#include "sway/config.h"
|
#include "sway/config.h"
|
||||||
#include "sway/swaynag.h"
|
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "stringop.h"
|
#include "stringop.h"
|
||||||
|
|
||||||
|
@ -42,14 +40,14 @@ struct cmd_results *output_cmd_background(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
struct output_config *output = config->handler_context.output_config;
|
struct output_config *output = config->handler_context.output_config;
|
||||||
|
char *src = NULL;
|
||||||
if (strcasecmp(argv[1], "solid_color") == 0) {
|
if (strcasecmp(argv[1], "solid_color") == 0) {
|
||||||
if (!validate_color(argv[0])) {
|
if (!validate_color(argv[0])) {
|
||||||
return cmd_results_new(CMD_INVALID,
|
return cmd_results_new(CMD_INVALID,
|
||||||
"Colors should be of the form #RRGGBB");
|
"Colors should be of the form #RRGGBB");
|
||||||
}
|
}
|
||||||
output->background = strdup(argv[0]);
|
if (!(output->background = strdup(argv[0]))) goto cleanup;
|
||||||
output->background_option = strdup("solid_color");
|
if (!(output->background_option = strdup("solid_color"))) goto cleanup;
|
||||||
output->background_fallback = NULL;
|
output->background_fallback = NULL;
|
||||||
argc -= 2; argv += 2;
|
argc -= 2; argv += 2;
|
||||||
} else {
|
} else {
|
||||||
|
@ -77,37 +75,25 @@ struct cmd_results *output_cmd_background(int argc, char **argv) {
|
||||||
return cmd_results_new(CMD_INVALID, "Missing background file");
|
return cmd_results_new(CMD_INVALID, "Missing background file");
|
||||||
}
|
}
|
||||||
|
|
||||||
char *src = join_args(argv, j);
|
if (!(src = join_args(argv, j))) goto cleanup;
|
||||||
if (!expand_path(&src)) {
|
if (!expand_path(&src)) {
|
||||||
struct cmd_results *cmd_res = cmd_results_new(CMD_INVALID,
|
struct cmd_results *cmd_res = cmd_results_new(CMD_INVALID,
|
||||||
"Invalid syntax (%s)", src);
|
"Invalid syntax (%s)", src);
|
||||||
free(src);
|
free(src);
|
||||||
return cmd_res;
|
return cmd_res;
|
||||||
}
|
}
|
||||||
if (!src) {
|
|
||||||
sway_log(SWAY_ERROR, "Failed to allocate expanded path");
|
|
||||||
return cmd_results_new(CMD_FAILURE, "Unable to allocate resource");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (config->reading && *src != '/') {
|
if (config->reading && *src != '/') {
|
||||||
// src file is inside configuration dir
|
// src file is inside configuration dir
|
||||||
|
|
||||||
char *conf = strdup(config->current_config_path);
|
char *conf = strdup(config->current_config_path);
|
||||||
if (!conf) {
|
if (!conf) goto cleanup;
|
||||||
sway_log(SWAY_ERROR, "Failed to duplicate string");
|
|
||||||
free(src);
|
|
||||||
return cmd_results_new(CMD_FAILURE,
|
|
||||||
"Unable to allocate resources");
|
|
||||||
}
|
|
||||||
|
|
||||||
char *conf_path = dirname(conf);
|
char *conf_path = dirname(conf);
|
||||||
char *real_src = malloc(strlen(conf_path) + strlen(src) + 2);
|
char *real_src = malloc(strlen(conf_path) + strlen(src) + 2);
|
||||||
if (!real_src) {
|
if (!real_src) {
|
||||||
free(src);
|
|
||||||
free(conf);
|
free(conf);
|
||||||
sway_log(SWAY_ERROR, "Unable to allocate memory");
|
goto cleanup;
|
||||||
return cmd_results_new(CMD_FAILURE,
|
|
||||||
"Unable to allocate resources");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(real_src, strlen(conf_path) + strlen(src) + 2, "%s/%s", conf_path, src);
|
snprintf(real_src, strlen(conf_path) + strlen(src) + 2, "%s/%s", conf_path, src);
|
||||||
|
@ -117,40 +103,48 @@ struct cmd_results *output_cmd_background(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool can_access = access(src, F_OK) != -1;
|
bool can_access = access(src, F_OK) != -1;
|
||||||
|
argc -= j + 1; argv += j + 1;
|
||||||
|
free(output->background_option);
|
||||||
|
free(output->background_fallback);
|
||||||
|
free(output->background);
|
||||||
|
output->background = output->background_option = output->background_fallback = NULL;
|
||||||
|
char *fallback = NULL;
|
||||||
|
|
||||||
|
if (argc && *argv[0] == '#') {
|
||||||
|
if (validate_color(argv[0])) {
|
||||||
|
if (!(fallback = strdup(argv[0]))) goto cleanup;
|
||||||
|
output->background_fallback = fallback;
|
||||||
|
} else {
|
||||||
|
sway_log(SWAY_ERROR, "fallback '%s' should be of the form #RRGGBB", argv[0]);
|
||||||
|
config_add_swaynag_warning("fallback '%s' should be of the form #RRGGBB\n", argv[0]);
|
||||||
|
}
|
||||||
|
argc--; argv++;
|
||||||
|
}
|
||||||
|
|
||||||
if (!can_access) {
|
if (!can_access) {
|
||||||
sway_log_errno(SWAY_ERROR, "Unable to access background file '%s'",
|
if (!fallback) {
|
||||||
src);
|
sway_log(SWAY_ERROR, "Unable to access background file '%s' "
|
||||||
config_add_swaynag_warning("Unable to access background file '%s'",
|
"and no valid fallback provided", src);
|
||||||
src);
|
struct cmd_results *res = cmd_results_new(CMD_FAILURE, "Unable to access "
|
||||||
struct cmd_results *result = cmd_results_new(CMD_FAILURE,
|
"background file '%s' and no valid fallback provided", src);
|
||||||
"unable to access background file '%s'", src);
|
free(src);
|
||||||
free(src);
|
return res;
|
||||||
return result;
|
}
|
||||||
|
sway_log(SWAY_DEBUG, "Cannot access file '%s', using fallback '%s'", src, fallback);
|
||||||
|
output->background = fallback;
|
||||||
|
if (!(output->background_option = strdup("solid_color"))) goto cleanup;
|
||||||
|
output->background_fallback = NULL;
|
||||||
} else {
|
} else {
|
||||||
output->background = src;
|
output->background = src;
|
||||||
output->background_option = strdup(mode);
|
if (!(output->background_option = strdup(mode))) goto cleanup;
|
||||||
}
|
|
||||||
argc -= j + 1; argv += j + 1;
|
|
||||||
|
|
||||||
output->background_fallback = NULL;
|
|
||||||
if (argc && *argv[0] == '#') {
|
|
||||||
if (!validate_color(argv[0])) {
|
|
||||||
return cmd_results_new(CMD_INVALID,
|
|
||||||
"fallback color should be of the form #RRGGBB");
|
|
||||||
}
|
|
||||||
|
|
||||||
output->background_fallback = strdup(argv[0]);
|
|
||||||
argc--; argv++;
|
|
||||||
|
|
||||||
if (!can_access) {
|
|
||||||
output->background = output->background_fallback;
|
|
||||||
output->background_option = strdup("solid_color");
|
|
||||||
output->background_fallback = NULL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
config->handler_context.leftovers.argc = argc;
|
config->handler_context.leftovers.argc = argc;
|
||||||
config->handler_context.leftovers.argv = argv;
|
config->handler_context.leftovers.argv = argv;
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
free(src);
|
||||||
|
sway_log(SWAY_ERROR, "Failed to allocate resources");
|
||||||
|
return cmd_results_new(CMD_FAILURE, "Unable to allocate resources");
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <wlr/render/color.h>
|
#include <wlr/render/color.h>
|
||||||
#include "sway/commands.h"
|
#include "sway/commands.h"
|
||||||
#include "sway/config.h"
|
#include "sway/config.h"
|
||||||
|
#include "stringop.h"
|
||||||
|
|
||||||
static bool read_file_into_buf(const char *path, void **buf, size_t *size) {
|
static bool read_file_into_buf(const char *path, void **buf, size_t *size) {
|
||||||
/* Why not use fopen/fread directly? glibc will succesfully open directories,
|
/* Why not use fopen/fread directly? glibc will succesfully open directories,
|
||||||
|
@ -70,12 +71,23 @@ struct cmd_results *output_cmd_color_profile(int argc, char **argv) {
|
||||||
return cmd_results_new(CMD_INVALID,
|
return cmd_results_new(CMD_INVALID,
|
||||||
"Invalid color profile specification: icc type requires a file");
|
"Invalid color profile specification: icc type requires a file");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *icc_path = strdup(argv[1]);
|
||||||
|
if (!expand_path(&icc_path)) {
|
||||||
|
struct cmd_results *cmd_res = cmd_results_new(CMD_INVALID,
|
||||||
|
"Invalid color profile specification: invalid file path");
|
||||||
|
free(icc_path);
|
||||||
|
return cmd_res;
|
||||||
|
}
|
||||||
|
|
||||||
void *data = NULL;
|
void *data = NULL;
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
if (!read_file_into_buf(argv[1], &data, &size)) {
|
if (!read_file_into_buf(icc_path, &data, &size)) {
|
||||||
|
free(icc_path);
|
||||||
return cmd_results_new(CMD_FAILURE,
|
return cmd_results_new(CMD_FAILURE,
|
||||||
"Failed to load color profile: could not read ICC file");
|
"Failed to load color profile: could not read ICC file");
|
||||||
}
|
}
|
||||||
|
free(icc_path);
|
||||||
|
|
||||||
struct wlr_color_transform *tmp =
|
struct wlr_color_transform *tmp =
|
||||||
wlr_color_transform_init_linear_to_icc(data, size);
|
wlr_color_transform_init_linear_to_icc(data, size);
|
||||||
|
|
|
@ -11,7 +11,10 @@ struct cmd_results *output_cmd_render_bit_depth(int argc, char **argv) {
|
||||||
return cmd_results_new(CMD_INVALID, "Missing bit depth argument.");
|
return cmd_results_new(CMD_INVALID, "Missing bit depth argument.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(*argv, "8") == 0) {
|
if (strcmp(*argv, "6") == 0) {
|
||||||
|
config->handler_context.output_config->render_bit_depth =
|
||||||
|
RENDER_BIT_DEPTH_6;
|
||||||
|
} else if (strcmp(*argv, "8") == 0) {
|
||||||
config->handler_context.output_config->render_bit_depth =
|
config->handler_context.output_config->render_bit_depth =
|
||||||
RENDER_BIT_DEPTH_8;
|
RENDER_BIT_DEPTH_8;
|
||||||
} else if (strcmp(*argv, "10") == 0) {
|
} else if (strcmp(*argv, "10") == 0) {
|
||||||
|
@ -19,7 +22,7 @@ struct cmd_results *output_cmd_render_bit_depth(int argc, char **argv) {
|
||||||
RENDER_BIT_DEPTH_10;
|
RENDER_BIT_DEPTH_10;
|
||||||
} else {
|
} else {
|
||||||
return cmd_results_new(CMD_INVALID,
|
return cmd_results_new(CMD_INVALID,
|
||||||
"Invalid bit depth. Must be a value in (8|10).");
|
"Invalid bit depth. Must be a value in (6|8|10).");
|
||||||
}
|
}
|
||||||
|
|
||||||
config->handler_context.leftovers.argc = argc - 1;
|
config->handler_context.leftovers.argc = argc - 1;
|
||||||
|
|
|
@ -118,10 +118,10 @@ struct cmd_results *cmd_scratchpad(int argc, char **argv) {
|
||||||
|
|
||||||
// If using criteria, this command is executed for every container which
|
// If using criteria, this command is executed for every container which
|
||||||
// matches the criteria. If this container isn't in the scratchpad,
|
// matches the criteria. If this container isn't in the scratchpad,
|
||||||
// we'll just silently return a success. The same is true if the
|
// we'll return an error. The same is true if the
|
||||||
// overridden node is not a container.
|
// overridden node is not a container.
|
||||||
if (!con || !con->scratchpad) {
|
if (!con || !con->scratchpad) {
|
||||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
return cmd_results_new(CMD_INVALID, "Container is not in scratchpad.");
|
||||||
}
|
}
|
||||||
scratchpad_toggle_container(con);
|
scratchpad_toggle_container(con);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
#define _POSIX_C_SOURCE 200809L
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "sway/commands.h"
|
#include "sway/commands.h"
|
||||||
#include "sway/config.h"
|
#include "sway/config.h"
|
||||||
|
@ -11,16 +12,19 @@ struct cmd_results *cmd_title_format(int argc, char **argv) {
|
||||||
return error;
|
return error;
|
||||||
}
|
}
|
||||||
struct sway_container *container = config->handler_context.container;
|
struct sway_container *container = config->handler_context.container;
|
||||||
if (!container || !container->view) {
|
if (!container) {
|
||||||
return cmd_results_new(CMD_INVALID,
|
return cmd_results_new(CMD_INVALID,
|
||||||
"Only views can have a title_format");
|
"Only valid containers can have a title_format");
|
||||||
}
|
}
|
||||||
struct sway_view *view = container->view;
|
|
||||||
char *format = join_args(argv, argc);
|
char *format = join_args(argv, argc);
|
||||||
if (view->title_format) {
|
if (container->title_format) {
|
||||||
free(view->title_format);
|
free(container->title_format);
|
||||||
|
}
|
||||||
|
container->title_format = format;
|
||||||
|
if (container->view) {
|
||||||
|
view_update_title(container->view, true);
|
||||||
|
} else {
|
||||||
|
container_update_representation(container);
|
||||||
}
|
}
|
||||||
view->title_format = format;
|
|
||||||
view_update_title(view, true);
|
|
||||||
return cmd_results_new(CMD_SUCCESS, NULL);
|
return cmd_results_new(CMD_SUCCESS, NULL);
|
||||||
}
|
}
|
||||||
|
|
|
@ -516,7 +516,7 @@ bool load_main_config(const char *file, bool is_active, bool validating) {
|
||||||
// Only really necessary if not explicitly `font` is set in the config.
|
// Only really necessary if not explicitly `font` is set in the config.
|
||||||
config_update_font_height();
|
config_update_font_height();
|
||||||
|
|
||||||
if (is_active && !validating) {
|
if (!validating) {
|
||||||
input_manager_verify_fallback_seat();
|
input_manager_verify_fallback_seat();
|
||||||
|
|
||||||
for (int i = 0; i < config->input_configs->length; i++) {
|
for (int i = 0; i < config->input_configs->length; i++) {
|
||||||
|
@ -533,12 +533,14 @@ bool load_main_config(const char *file, bool is_active, bool validating) {
|
||||||
}
|
}
|
||||||
sway_switch_retrigger_bindings_for_all();
|
sway_switch_retrigger_bindings_for_all();
|
||||||
|
|
||||||
apply_all_output_configs();
|
|
||||||
spawn_swaybg();
|
spawn_swaybg();
|
||||||
|
|
||||||
config->reloading = false;
|
config->reloading = false;
|
||||||
if (config->swaynag_config_errors.client != NULL) {
|
if (is_active) {
|
||||||
swaynag_show(&config->swaynag_config_errors);
|
request_modeset();
|
||||||
|
if (config->swaynag_config_errors.client != NULL) {
|
||||||
|
swaynag_show(&config->swaynag_config_errors);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -923,8 +925,8 @@ char *do_var_replacement(char *str) {
|
||||||
// Find matching variable
|
// Find matching variable
|
||||||
for (i = 0; i < config->symbols->length; ++i) {
|
for (i = 0; i < config->symbols->length; ++i) {
|
||||||
struct sway_variable *var = config->symbols->items[i];
|
struct sway_variable *var = config->symbols->items[i];
|
||||||
int vnlen = strlen(var->name);
|
if (has_prefix(find, var->name)) {
|
||||||
if (strncmp(find, var->name, vnlen) == 0) {
|
int vnlen = strlen(var->name);
|
||||||
int vvlen = strlen(var->value);
|
int vvlen = strlen(var->value);
|
||||||
char *newstr = malloc(strlen(str) - vnlen + vvlen + 1);
|
char *newstr = malloc(strlen(str) - vnlen + vvlen + 1);
|
||||||
if (!newstr) {
|
if (!newstr) {
|
||||||
|
|
|
@ -213,36 +213,23 @@ static void invoke_swaybar(struct bar_config *bar) {
|
||||||
sway_log(SWAY_ERROR, "Failed to create fork for swaybar");
|
sway_log(SWAY_ERROR, "Failed to create fork for swaybar");
|
||||||
return;
|
return;
|
||||||
} else if (pid == 0) {
|
} else if (pid == 0) {
|
||||||
// Remove the SIGUSR1 handler that wlroots adds for xwayland
|
|
||||||
sigset_t set;
|
|
||||||
sigemptyset(&set);
|
|
||||||
sigprocmask(SIG_SETMASK, &set, NULL);
|
|
||||||
signal(SIGPIPE, SIG_DFL);
|
|
||||||
|
|
||||||
restore_nofile_limit();
|
restore_nofile_limit();
|
||||||
|
restore_signals();
|
||||||
pid = fork();
|
if (!sway_set_cloexec(sockets[1], false)) {
|
||||||
if (pid < 0) {
|
|
||||||
sway_log_errno(SWAY_ERROR, "fork failed");
|
|
||||||
_exit(EXIT_FAILURE);
|
|
||||||
} else if (pid == 0) {
|
|
||||||
if (!sway_set_cloexec(sockets[1], false)) {
|
|
||||||
_exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
char wayland_socket_str[16];
|
|
||||||
snprintf(wayland_socket_str, sizeof(wayland_socket_str),
|
|
||||||
"%d", sockets[1]);
|
|
||||||
setenv("WAYLAND_SOCKET", wayland_socket_str, true);
|
|
||||||
|
|
||||||
// run custom swaybar
|
|
||||||
char *const cmd[] = {
|
|
||||||
bar->swaybar_command ? bar->swaybar_command : "swaybar",
|
|
||||||
"-b", bar->id, NULL};
|
|
||||||
execvp(cmd[0], cmd);
|
|
||||||
_exit(EXIT_FAILURE);
|
_exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
_exit(EXIT_SUCCESS);
|
|
||||||
|
char wayland_socket_str[16];
|
||||||
|
snprintf(wayland_socket_str, sizeof(wayland_socket_str),
|
||||||
|
"%d", sockets[1]);
|
||||||
|
setenv("WAYLAND_SOCKET", wayland_socket_str, true);
|
||||||
|
|
||||||
|
// run custom swaybar
|
||||||
|
char *const cmd[] = {
|
||||||
|
bar->swaybar_command ? bar->swaybar_command : "swaybar",
|
||||||
|
"-b", bar->id, NULL};
|
||||||
|
execvp(cmd[0], cmd);
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (close(sockets[1]) != 0) {
|
if (close(sockets[1]) != 0) {
|
||||||
|
@ -250,11 +237,6 @@ static void invoke_swaybar(struct bar_config *bar) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (waitpid(pid, NULL, 0) < 0) {
|
|
||||||
sway_log_errno(SWAY_ERROR, "waitpid failed");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
sway_log(SWAY_DEBUG, "Spawned swaybar %s", bar->id);
|
sway_log(SWAY_DEBUG, "Spawned swaybar %s", bar->id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -300,7 +300,7 @@ struct input_config *store_input_config(struct input_config *ic,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool type = strncmp(ic->identifier, "type:", strlen("type:")) == 0;
|
bool type = has_prefix(ic->identifier, "type:");
|
||||||
if (type && error && !validate_type_on_existing(ic, error)) {
|
if (type && error && !validate_type_on_existing(ic, error)) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,14 +6,20 @@
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <wlr/config.h>
|
#include <wlr/config.h>
|
||||||
|
#include <wlr/render/allocator.h>
|
||||||
#include <wlr/types/wlr_cursor.h>
|
#include <wlr/types/wlr_cursor.h>
|
||||||
#include <wlr/types/wlr_output_layout.h>
|
#include <wlr/types/wlr_output_layout.h>
|
||||||
#include <wlr/types/wlr_output.h>
|
#include <wlr/types/wlr_output.h>
|
||||||
#include <wlr/types/wlr_output_swapchain_manager.h>
|
#include <wlr/types/wlr_output_swapchain_manager.h>
|
||||||
|
#include <xf86drm.h>
|
||||||
#include "sway/config.h"
|
#include "sway/config.h"
|
||||||
|
#include "sway/desktop/transaction.h"
|
||||||
#include "sway/input/cursor.h"
|
#include "sway/input/cursor.h"
|
||||||
|
#include "sway/layers.h"
|
||||||
|
#include "sway/lock.h"
|
||||||
#include "sway/output.h"
|
#include "sway/output.h"
|
||||||
#include "sway/server.h"
|
#include "sway/server.h"
|
||||||
|
#include "sway/tree/arrange.h"
|
||||||
#include "sway/tree/root.h"
|
#include "sway/tree/root.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
@ -22,13 +28,6 @@
|
||||||
#include <wlr/backend/drm.h>
|
#include <wlr/backend/drm.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int output_name_cmp(const void *item, const void *data) {
|
|
||||||
const struct output_config *output = item;
|
|
||||||
const char *name = data;
|
|
||||||
|
|
||||||
return strcmp(output->name, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
void output_get_identifier(char *identifier, size_t len,
|
void output_get_identifier(char *identifier, size_t len,
|
||||||
struct sway_output *output) {
|
struct sway_output *output) {
|
||||||
struct wlr_output *wlr_output = output->wlr_output;
|
struct wlr_output *wlr_output = output->wlr_output;
|
||||||
|
@ -79,6 +78,7 @@ struct output_config *new_output_config(const char *name) {
|
||||||
oc->set_color_transform = false;
|
oc->set_color_transform = false;
|
||||||
oc->color_transform = NULL;
|
oc->color_transform = NULL;
|
||||||
oc->power = -1;
|
oc->power = -1;
|
||||||
|
oc->allow_tearing = -1;
|
||||||
return oc;
|
return oc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,6 +216,9 @@ static void merge_output_config(struct output_config *dst, struct output_config
|
||||||
if (src->power != -1) {
|
if (src->power != -1) {
|
||||||
dst->power = src->power;
|
dst->power = src->power;
|
||||||
}
|
}
|
||||||
|
if (src->allow_tearing != -1) {
|
||||||
|
dst->allow_tearing = src->allow_tearing;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void store_output_config(struct output_config *oc) {
|
void store_output_config(struct output_config *oc) {
|
||||||
|
@ -258,11 +261,11 @@ void store_output_config(struct output_config *oc) {
|
||||||
|
|
||||||
sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz "
|
sway_log(SWAY_DEBUG, "Config stored for output %s (enabled: %d) (%dx%d@%fHz "
|
||||||
"position %d,%d scale %f subpixel %s transform %d) (bg %s %s) (power %d) "
|
"position %d,%d scale %f subpixel %s transform %d) (bg %s %s) (power %d) "
|
||||||
"(max render time: %d)",
|
"(max render time: %d) (allow tearing: %d)",
|
||||||
oc->name, oc->enabled, oc->width, oc->height, oc->refresh_rate,
|
oc->name, oc->enabled, oc->width, oc->height, oc->refresh_rate,
|
||||||
oc->x, oc->y, oc->scale, sway_wl_output_subpixel_to_string(oc->subpixel),
|
oc->x, oc->y, oc->scale, sway_wl_output_subpixel_to_string(oc->subpixel),
|
||||||
oc->transform, oc->background, oc->background_option, oc->power,
|
oc->transform, oc->background, oc->background_option, oc->power,
|
||||||
oc->max_render_time);
|
oc->max_render_time, oc->allow_tearing);
|
||||||
|
|
||||||
// If the configuration was not merged into an existing configuration, add
|
// If the configuration was not merged into an existing configuration, add
|
||||||
// it to the list. Otherwise we're done with it and can free it.
|
// it to the list. Otherwise we're done with it and can free it.
|
||||||
|
@ -283,7 +286,6 @@ static void set_mode(struct wlr_output *output, struct wlr_output_state *pending
|
||||||
mhz = mhz <= 0 ? INT_MAX : mhz;
|
mhz = mhz <= 0 ? INT_MAX : mhz;
|
||||||
|
|
||||||
if (wl_list_empty(&output->modes) || custom) {
|
if (wl_list_empty(&output->modes) || custom) {
|
||||||
sway_log(SWAY_DEBUG, "Assigning custom mode to %s", output->name);
|
|
||||||
wlr_output_state_set_custom_mode(pending, width, height,
|
wlr_output_state_set_custom_mode(pending, width, height,
|
||||||
refresh_rate > 0 ? mhz : 0);
|
refresh_rate > 0 ? mhz : 0);
|
||||||
return;
|
return;
|
||||||
|
@ -303,10 +305,7 @@ static void set_mode(struct wlr_output *output, struct wlr_output_state *pending
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (best) {
|
if (!best) {
|
||||||
sway_log(SWAY_INFO, "Assigning configured mode (%dx%d@%.3fHz) to %s",
|
|
||||||
best->width, best->height, best->refresh / 1000.f, output->name);
|
|
||||||
} else {
|
|
||||||
best = wlr_output_preferred_mode(output);
|
best = wlr_output_preferred_mode(output);
|
||||||
sway_log(SWAY_INFO, "Configured mode (%dx%d@%.3fHz) not available, "
|
sway_log(SWAY_INFO, "Configured mode (%dx%d@%.3fHz) not available, "
|
||||||
"applying preferred mode (%dx%d@%.3fHz)",
|
"applying preferred mode (%dx%d@%.3fHz)",
|
||||||
|
@ -323,7 +322,6 @@ static void set_modeline(struct wlr_output *output,
|
||||||
sway_log(SWAY_ERROR, "Modeline can only be set to DRM output");
|
sway_log(SWAY_ERROR, "Modeline can only be set to DRM output");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sway_log(SWAY_DEBUG, "Assigning custom modeline to %s", output->name);
|
|
||||||
struct wlr_output_mode *mode = wlr_drm_connector_add_mode(output, drm_mode);
|
struct wlr_output_mode *mode = wlr_drm_connector_add_mode(output, drm_mode);
|
||||||
if (mode) {
|
if (mode) {
|
||||||
wlr_output_state_set_mode(pending, mode);
|
wlr_output_state_set_mode(pending, mode);
|
||||||
|
@ -389,7 +387,6 @@ static int compute_default_scale(struct wlr_output *output,
|
||||||
|
|
||||||
double dpi_x = (double) width / (output->phys_width / MM_PER_INCH);
|
double dpi_x = (double) width / (output->phys_width / MM_PER_INCH);
|
||||||
double dpi_y = (double) height / (output->phys_height / MM_PER_INCH);
|
double dpi_y = (double) height / (output->phys_height / MM_PER_INCH);
|
||||||
sway_log(SWAY_DEBUG, "Output DPI: %fx%f", dpi_x, dpi_y);
|
|
||||||
if (dpi_x <= HIDPI_DPI_LIMIT || dpi_y <= HIDPI_DPI_LIMIT) {
|
if (dpi_x <= HIDPI_DPI_LIMIT || dpi_y <= HIDPI_DPI_LIMIT) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -397,9 +394,15 @@ static int compute_default_scale(struct wlr_output *output,
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool render_format_is_10bit(uint32_t render_format) {
|
static enum render_bit_depth bit_depth_from_format(uint32_t render_format) {
|
||||||
return render_format == DRM_FORMAT_XRGB2101010 ||
|
if (render_format == DRM_FORMAT_XRGB2101010 || render_format == DRM_FORMAT_XBGR2101010) {
|
||||||
render_format == DRM_FORMAT_XBGR2101010;
|
return RENDER_BIT_DEPTH_10;
|
||||||
|
} else if (render_format == DRM_FORMAT_XRGB8888 || render_format == DRM_FORMAT_ARGB8888) {
|
||||||
|
return RENDER_BIT_DEPTH_8;
|
||||||
|
} else if (render_format == DRM_FORMAT_RGB565) {
|
||||||
|
return RENDER_BIT_DEPTH_6;
|
||||||
|
}
|
||||||
|
return RENDER_BIT_DEPTH_DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool render_format_is_bgr(uint32_t fmt) {
|
static bool render_format_is_bgr(uint32_t fmt) {
|
||||||
|
@ -419,90 +422,73 @@ static void queue_output_config(struct output_config *oc,
|
||||||
struct wlr_output *wlr_output = output->wlr_output;
|
struct wlr_output *wlr_output = output->wlr_output;
|
||||||
|
|
||||||
if (output_config_is_disabling(oc)) {
|
if (output_config_is_disabling(oc)) {
|
||||||
sway_log(SWAY_DEBUG, "Turning off output %s", wlr_output->name);
|
|
||||||
wlr_output_state_set_enabled(pending, false);
|
wlr_output_state_set_enabled(pending, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
sway_log(SWAY_DEBUG, "Turning on output %s", wlr_output->name);
|
|
||||||
wlr_output_state_set_enabled(pending, true);
|
wlr_output_state_set_enabled(pending, true);
|
||||||
|
|
||||||
if (oc && oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t) -1) {
|
if (oc && oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t) -1) {
|
||||||
sway_log(SWAY_DEBUG, "Set %s modeline",
|
|
||||||
wlr_output->name);
|
|
||||||
set_modeline(wlr_output, pending, &oc->drm_mode);
|
set_modeline(wlr_output, pending, &oc->drm_mode);
|
||||||
} else if (oc && oc->width > 0 && oc->height > 0) {
|
} else if (oc && oc->width > 0 && oc->height > 0) {
|
||||||
sway_log(SWAY_DEBUG, "Set %s mode to %dx%d (%f Hz)",
|
|
||||||
wlr_output->name, oc->width, oc->height, oc->refresh_rate);
|
|
||||||
set_mode(wlr_output, pending, oc->width, oc->height,
|
set_mode(wlr_output, pending, oc->width, oc->height,
|
||||||
oc->refresh_rate, oc->custom_mode == 1);
|
oc->refresh_rate, oc->custom_mode == 1);
|
||||||
} else if (!wl_list_empty(&wlr_output->modes)) {
|
} else if (!wl_list_empty(&wlr_output->modes)) {
|
||||||
sway_log(SWAY_DEBUG, "Set preferred mode");
|
|
||||||
struct wlr_output_mode *preferred_mode =
|
struct wlr_output_mode *preferred_mode =
|
||||||
wlr_output_preferred_mode(wlr_output);
|
wlr_output_preferred_mode(wlr_output);
|
||||||
wlr_output_state_set_mode(pending, preferred_mode);
|
wlr_output_state_set_mode(pending, preferred_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oc && (oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN || config->reloading)) {
|
if (oc && oc->subpixel != WL_OUTPUT_SUBPIXEL_UNKNOWN) {
|
||||||
sway_log(SWAY_DEBUG, "Set %s subpixel to %s", oc->name,
|
|
||||||
sway_wl_output_subpixel_to_string(oc->subpixel));
|
|
||||||
wlr_output_state_set_subpixel(pending, oc->subpixel);
|
wlr_output_state_set_subpixel(pending, oc->subpixel);
|
||||||
|
} else {
|
||||||
|
wlr_output_state_set_subpixel(pending, output->detected_subpixel);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum wl_output_transform tr = WL_OUTPUT_TRANSFORM_NORMAL;
|
|
||||||
if (oc && oc->transform >= 0) {
|
if (oc && oc->transform >= 0) {
|
||||||
tr = oc->transform;
|
wlr_output_state_set_transform(pending, oc->transform);
|
||||||
#if WLR_HAS_DRM_BACKEND
|
#if WLR_HAS_DRM_BACKEND
|
||||||
} else if (wlr_output_is_drm(wlr_output)) {
|
} else if (wlr_output_is_drm(wlr_output)) {
|
||||||
tr = wlr_drm_connector_get_panel_orientation(wlr_output);
|
wlr_output_state_set_transform(pending,
|
||||||
sway_log(SWAY_DEBUG, "Auto-detected output transform: %d", tr);
|
wlr_drm_connector_get_panel_orientation(wlr_output));
|
||||||
#endif
|
#endif
|
||||||
}
|
} else {
|
||||||
if (wlr_output->transform != tr) {
|
wlr_output_state_set_transform(pending, WL_OUTPUT_TRANSFORM_NORMAL);
|
||||||
sway_log(SWAY_DEBUG, "Set %s transform to %d", wlr_output->name, tr);
|
|
||||||
wlr_output_state_set_transform(pending, tr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the scale last before the commit, because the scale auto-detection
|
// Apply the scale after sorting out the mode, because the scale
|
||||||
// reads the pending output size
|
// auto-detection reads the pending output size
|
||||||
float scale;
|
|
||||||
if (oc && oc->scale > 0) {
|
if (oc && oc->scale > 0) {
|
||||||
scale = oc->scale;
|
|
||||||
|
|
||||||
// The factional-scale-v1 protocol uses increments of 120ths to send
|
// The factional-scale-v1 protocol uses increments of 120ths to send
|
||||||
// the scale factor to the client. Adjust the scale so that we use the
|
// the scale factor to the client. Adjust the scale so that we use the
|
||||||
// same value as the clients'.
|
// same value as the clients'.
|
||||||
float adjusted_scale = round(scale * 120) / 120;
|
wlr_output_state_set_scale(pending, round(oc->scale * 120) / 120);
|
||||||
if (scale != adjusted_scale) {
|
|
||||||
sway_log(SWAY_INFO, "Adjusting output scale from %f to %f",
|
|
||||||
scale, adjusted_scale);
|
|
||||||
scale = adjusted_scale;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
scale = compute_default_scale(wlr_output, pending);
|
wlr_output_state_set_scale(pending,
|
||||||
sway_log(SWAY_DEBUG, "Auto-detected output scale: %f", scale);
|
compute_default_scale(wlr_output, pending));
|
||||||
}
|
|
||||||
if (scale != wlr_output->scale) {
|
|
||||||
sway_log(SWAY_DEBUG, "Set %s scale to %f", wlr_output->name, scale);
|
|
||||||
wlr_output_state_set_scale(pending, scale);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oc && oc->adaptive_sync != -1) {
|
if (wlr_output->adaptive_sync_supported) {
|
||||||
sway_log(SWAY_DEBUG, "Set %s adaptive sync to %d", wlr_output->name,
|
if (oc && oc->adaptive_sync != -1) {
|
||||||
oc->adaptive_sync);
|
wlr_output_state_set_adaptive_sync_enabled(pending, oc->adaptive_sync == 1);
|
||||||
wlr_output_state_set_adaptive_sync_enabled(pending, oc->adaptive_sync == 1);
|
} else {
|
||||||
|
wlr_output_state_set_adaptive_sync_enabled(pending, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
|
if (oc && oc->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
|
||||||
if (oc->render_bit_depth == RENDER_BIT_DEPTH_10 &&
|
if (oc->render_bit_depth == RENDER_BIT_DEPTH_10 &&
|
||||||
render_format_is_10bit(output->wlr_output->render_format)) {
|
bit_depth_from_format(output->wlr_output->render_format) == oc->render_bit_depth) {
|
||||||
// 10-bit was set successfully before, try to save some tests by reusing the format
|
// 10-bit was set successfully before, try to save some tests by reusing the format
|
||||||
wlr_output_state_set_render_format(pending, output->wlr_output->render_format);
|
wlr_output_state_set_render_format(pending, output->wlr_output->render_format);
|
||||||
} else if (oc->render_bit_depth == RENDER_BIT_DEPTH_10) {
|
} else if (oc->render_bit_depth == RENDER_BIT_DEPTH_10) {
|
||||||
wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB2101010);
|
wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB2101010);
|
||||||
|
} else if (oc->render_bit_depth == RENDER_BIT_DEPTH_6){
|
||||||
|
wlr_output_state_set_render_format(pending, DRM_FORMAT_RGB565);
|
||||||
} else {
|
} else {
|
||||||
wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB8888);
|
wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB8888);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
wlr_output_state_set_render_format(pending, DRM_FORMAT_XRGB8888);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,24 +507,23 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oc) {
|
enum scale_filter_mode scale_filter_old = output->scale_filter;
|
||||||
enum scale_filter_mode scale_filter_old = output->scale_filter;
|
enum scale_filter_mode scale_filter_new = oc ? oc->scale_filter : SCALE_FILTER_DEFAULT;
|
||||||
switch (oc->scale_filter) {
|
switch (scale_filter_new) {
|
||||||
case SCALE_FILTER_DEFAULT:
|
case SCALE_FILTER_DEFAULT:
|
||||||
case SCALE_FILTER_SMART:
|
case SCALE_FILTER_SMART:
|
||||||
output->scale_filter = ceilf(wlr_output->scale) == wlr_output->scale ?
|
output->scale_filter = ceilf(wlr_output->scale) == wlr_output->scale ?
|
||||||
SCALE_FILTER_NEAREST : SCALE_FILTER_LINEAR;
|
SCALE_FILTER_NEAREST : SCALE_FILTER_LINEAR;
|
||||||
break;
|
break;
|
||||||
case SCALE_FILTER_LINEAR:
|
case SCALE_FILTER_LINEAR:
|
||||||
case SCALE_FILTER_NEAREST:
|
case SCALE_FILTER_NEAREST:
|
||||||
output->scale_filter = oc->scale_filter;
|
output->scale_filter = scale_filter_new;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (scale_filter_old != output->scale_filter) {
|
if (scale_filter_old != output->scale_filter) {
|
||||||
sway_log(SWAY_DEBUG, "Set %s scale_filter to %s", oc->name,
|
sway_log(SWAY_DEBUG, "Set %s scale_filter to %s", oc->name,
|
||||||
sway_output_scale_filter_to_string(output->scale_filter));
|
sway_output_scale_filter_to_string(output->scale_filter));
|
||||||
wlr_damage_ring_add_whole(&output->scene_output->damage_ring);
|
wlr_damage_ring_add_whole(&output->scene_output->damage_ring);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find position for it
|
// Find position for it
|
||||||
|
@ -549,99 +534,76 @@ static bool finalize_output_config(struct output_config *oc, struct sway_output
|
||||||
wlr_output_layout_add_auto(root->output_layout, wlr_output);
|
wlr_output_layout_add_auto(root->output_layout, wlr_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update output->{lx, ly, width, height}
|
|
||||||
struct wlr_box output_box;
|
|
||||||
wlr_output_layout_get_box(root->output_layout, wlr_output, &output_box);
|
|
||||||
output->lx = output_box.x;
|
|
||||||
output->ly = output_box.y;
|
|
||||||
output->width = output_box.width;
|
|
||||||
output->height = output_box.height;
|
|
||||||
|
|
||||||
if (!output->enabled) {
|
if (!output->enabled) {
|
||||||
output_enable(output);
|
output_enable(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (oc && oc->max_render_time >= 0) {
|
|
||||||
sway_log(SWAY_DEBUG, "Set %s max render time to %d",
|
|
||||||
oc->name, oc->max_render_time);
|
|
||||||
output->max_render_time = oc->max_render_time;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oc && oc->set_color_transform) {
|
if (oc && oc->set_color_transform) {
|
||||||
if (oc->color_transform) {
|
if (oc->color_transform) {
|
||||||
wlr_color_transform_ref(oc->color_transform);
|
wlr_color_transform_ref(oc->color_transform);
|
||||||
}
|
}
|
||||||
wlr_color_transform_unref(output->color_transform);
|
wlr_color_transform_unref(output->color_transform);
|
||||||
output->color_transform = oc->color_transform;
|
output->color_transform = oc->color_transform;
|
||||||
|
} else {
|
||||||
|
wlr_color_transform_unref(output->color_transform);
|
||||||
|
output->color_transform = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
output->max_render_time = oc && oc->max_render_time > 0 ? oc->max_render_time : 0;
|
||||||
|
output->allow_tearing = oc && oc->allow_tearing > 0;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void default_output_config(struct output_config *oc,
|
static void output_update_position(struct sway_output *output) {
|
||||||
struct wlr_output *wlr_output) {
|
struct wlr_box output_box;
|
||||||
oc->enabled = 1;
|
wlr_output_layout_get_box(root->output_layout, output->wlr_output, &output_box);
|
||||||
oc->power = 1;
|
output->lx = output_box.x;
|
||||||
struct wlr_output_mode *mode = wlr_output_preferred_mode(wlr_output);
|
output->ly = output_box.y;
|
||||||
if (mode != NULL) {
|
output->width = output_box.width;
|
||||||
oc->width = mode->width;
|
output->height = output_box.height;
|
||||||
oc->height = mode->height;
|
|
||||||
oc->refresh_rate = mode->refresh / 1000.f;
|
|
||||||
}
|
|
||||||
oc->x = oc->y = -1;
|
|
||||||
oc->scale = 0; // auto
|
|
||||||
oc->scale_filter = SCALE_FILTER_DEFAULT;
|
|
||||||
struct sway_output *output = wlr_output->data;
|
|
||||||
oc->subpixel = output->detected_subpixel;
|
|
||||||
oc->transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
|
||||||
oc->max_render_time = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// find_output_config returns a merged output_config containing all stored
|
// find_output_config_from_list returns a merged output_config containing all
|
||||||
// configuration that applies to the specified output.
|
// stored configuration that applies to the specified output.
|
||||||
struct output_config *find_output_config(struct sway_output *sway_output) {
|
static struct output_config *find_output_config_from_list(
|
||||||
|
struct output_config **configs, size_t configs_len,
|
||||||
|
struct sway_output *sway_output) {
|
||||||
const char *name = sway_output->wlr_output->name;
|
const char *name = sway_output->wlr_output->name;
|
||||||
struct output_config *oc = NULL;
|
|
||||||
|
|
||||||
struct output_config *result = new_output_config(name);
|
struct output_config *result = new_output_config(name);
|
||||||
if (config->reloading) {
|
if (result == NULL) {
|
||||||
default_output_config(result, sway_output->wlr_output);
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
char id[128];
|
char id[128];
|
||||||
output_get_identifier(id, sizeof(id), sway_output);
|
output_get_identifier(id, sizeof(id), sway_output);
|
||||||
|
|
||||||
int i;
|
// We take a new config and merge on top, in order, the wildcard config,
|
||||||
bool match = false;
|
// output config by name, and output config by identifier to form the final
|
||||||
if ((i = list_seq_find(config->output_configs, output_name_cmp, "*")) >= 0) {
|
// config. If there are multiple matches, they are merged in order.
|
||||||
match = true;
|
struct output_config *oc = NULL;
|
||||||
oc = config->output_configs->items[i];
|
const char *names[] = {"*", name, id, NULL};
|
||||||
merge_output_config(result, oc);
|
for (const char **name = &names[0]; *name; name++) {
|
||||||
}
|
for (size_t idx = 0; idx < configs_len; idx++) {
|
||||||
if ((i = list_seq_find(config->output_configs, output_name_cmp, name)) >= 0) {
|
oc = configs[idx];
|
||||||
match = true;
|
if (strcmp(oc->name, *name) == 0) {
|
||||||
oc = config->output_configs->items[i];
|
merge_output_config(result, oc);
|
||||||
merge_output_config(result, oc);
|
}
|
||||||
}
|
}
|
||||||
if ((i = list_seq_find(config->output_configs, output_name_cmp, id)) >= 0) {
|
|
||||||
match = true;
|
|
||||||
oc = config->output_configs->items[i];
|
|
||||||
merge_output_config(result, oc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!match && !config->reloading) {
|
|
||||||
// No name, identifier, or wildcard config. Since we are not
|
|
||||||
// reloading with defaults, the output config will be empty, so
|
|
||||||
// just return NULL
|
|
||||||
free_output_config(result);
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool config_has_auto_mode(struct output_config *oc) {
|
struct output_config *find_output_config(struct sway_output *sway_output) {
|
||||||
|
return find_output_config_from_list(
|
||||||
|
(struct output_config **)config->output_configs->items,
|
||||||
|
config->output_configs->length, sway_output);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool config_has_manual_mode(struct output_config *oc) {
|
||||||
if (!oc) {
|
if (!oc) {
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
if (oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t)-1) {
|
if (oc->drm_mode.type != 0 && oc->drm_mode.type != (uint32_t)-1) {
|
||||||
return true;
|
return true;
|
||||||
|
@ -651,6 +613,14 @@ static bool config_has_auto_mode(struct output_config *oc) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An output config pre-matched to an output
|
||||||
|
*/
|
||||||
|
struct matched_output_config {
|
||||||
|
struct sway_output *output;
|
||||||
|
struct output_config *config;
|
||||||
|
};
|
||||||
|
|
||||||
struct search_context {
|
struct search_context {
|
||||||
struct wlr_output_swapchain_manager *swapchain_mgr;
|
struct wlr_output_swapchain_manager *swapchain_mgr;
|
||||||
struct wlr_backend_output_state *states;
|
struct wlr_backend_output_state *states;
|
||||||
|
@ -665,7 +635,9 @@ static void dump_output_state(struct wlr_output *wlr_output, struct wlr_output_s
|
||||||
sway_log(SWAY_DEBUG, " enabled: %s", state->enabled ? "yes" : "no");
|
sway_log(SWAY_DEBUG, " enabled: %s", state->enabled ? "yes" : "no");
|
||||||
}
|
}
|
||||||
if (state->committed & WLR_OUTPUT_STATE_RENDER_FORMAT) {
|
if (state->committed & WLR_OUTPUT_STATE_RENDER_FORMAT) {
|
||||||
sway_log(SWAY_DEBUG, " render_format: %d", state->render_format);
|
char *format_name = drmGetFormatName(state->render_format);
|
||||||
|
sway_log(SWAY_DEBUG, " render_format: %s", format_name);
|
||||||
|
free(format_name);
|
||||||
}
|
}
|
||||||
if (state->committed & WLR_OUTPUT_STATE_MODE) {
|
if (state->committed & WLR_OUTPUT_STATE_MODE) {
|
||||||
if (state->mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM) {
|
if (state->mode_type == WLR_OUTPUT_STATE_MODE_CUSTOM) {
|
||||||
|
@ -681,6 +653,13 @@ static void dump_output_state(struct wlr_output *wlr_output, struct wlr_output_s
|
||||||
sway_log(SWAY_DEBUG, " adaptive_sync: %s",
|
sway_log(SWAY_DEBUG, " adaptive_sync: %s",
|
||||||
state->adaptive_sync_enabled ? "enabled": "disabled");
|
state->adaptive_sync_enabled ? "enabled": "disabled");
|
||||||
}
|
}
|
||||||
|
if (state->committed & WLR_OUTPUT_STATE_SCALE) {
|
||||||
|
sway_log(SWAY_DEBUG, " scale: %f", state->scale);
|
||||||
|
}
|
||||||
|
if (state->committed & WLR_OUTPUT_STATE_SUBPIXEL) {
|
||||||
|
sway_log(SWAY_DEBUG, " subpixel: %s",
|
||||||
|
sway_wl_output_subpixel_to_string(state->subpixel));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool search_valid_config(struct search_context *ctx, size_t output_idx);
|
static bool search_valid_config(struct search_context *ctx, size_t output_idx);
|
||||||
|
@ -742,7 +721,8 @@ static bool search_mode(struct search_context *ctx, size_t output_idx) {
|
||||||
struct wlr_output_state *state = &backend_state->base;
|
struct wlr_output_state *state = &backend_state->base;
|
||||||
struct wlr_output *wlr_output = backend_state->output;
|
struct wlr_output *wlr_output = backend_state->output;
|
||||||
|
|
||||||
if (!config_has_auto_mode(cfg->config)) {
|
// We only search for mode if one is not explicitly specified in the config
|
||||||
|
if (config_has_manual_mode(cfg->config)) {
|
||||||
return search_adaptive_sync(ctx, output_idx);
|
return search_adaptive_sync(ctx, output_idx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -783,6 +763,8 @@ static bool search_render_format(struct search_context *ctx, size_t output_idx)
|
||||||
DRM_FORMAT_XRGB2101010,
|
DRM_FORMAT_XRGB2101010,
|
||||||
DRM_FORMAT_XBGR2101010,
|
DRM_FORMAT_XBGR2101010,
|
||||||
DRM_FORMAT_XRGB8888,
|
DRM_FORMAT_XRGB8888,
|
||||||
|
DRM_FORMAT_ARGB8888,
|
||||||
|
DRM_FORMAT_RGB565,
|
||||||
DRM_FORMAT_INVALID,
|
DRM_FORMAT_INVALID,
|
||||||
};
|
};
|
||||||
if (render_format_is_bgr(wlr_output->render_format)) {
|
if (render_format_is_bgr(wlr_output->render_format)) {
|
||||||
|
@ -792,13 +774,18 @@ static bool search_render_format(struct search_context *ctx, size_t output_idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
const struct wlr_drm_format_set *primary_formats =
|
const struct wlr_drm_format_set *primary_formats =
|
||||||
wlr_output_get_primary_formats(wlr_output, WLR_BUFFER_CAP_DMABUF);
|
wlr_output_get_primary_formats(wlr_output, server.allocator->buffer_caps);
|
||||||
bool need_10bit = cfg->config && cfg->config->render_bit_depth == RENDER_BIT_DEPTH_10;
|
enum render_bit_depth needed_bits = RENDER_BIT_DEPTH_8;
|
||||||
|
if (cfg->config && cfg->config->render_bit_depth != RENDER_BIT_DEPTH_DEFAULT) {
|
||||||
|
needed_bits = cfg->config->render_bit_depth;
|
||||||
|
}
|
||||||
for (size_t idx = 0; fmts[idx] != DRM_FORMAT_INVALID; idx++) {
|
for (size_t idx = 0; fmts[idx] != DRM_FORMAT_INVALID; idx++) {
|
||||||
if (!need_10bit && render_format_is_10bit(fmts[idx])) {
|
enum render_bit_depth format_bits = bit_depth_from_format(fmts[idx]);
|
||||||
|
if (needed_bits < format_bits) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (!wlr_drm_format_set_get(primary_formats, fmts[idx])) {
|
// If primary_formats is NULL, all formats are supported
|
||||||
|
if (primary_formats && !wlr_drm_format_set_get(primary_formats, fmts[idx])) {
|
||||||
// This is not a supported format for this output
|
// This is not a supported format for this output
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -868,12 +855,12 @@ static int compare_matched_output_config_priority(const void *a, const void *b)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void sort_output_configs_by_priority(struct matched_output_config *configs,
|
static void sort_output_configs_by_priority(
|
||||||
size_t configs_len) {
|
struct matched_output_config *configs, size_t configs_len) {
|
||||||
qsort(configs, configs_len, sizeof(*configs), compare_matched_output_config_priority);
|
qsort(configs, configs_len, sizeof(*configs), compare_matched_output_config_priority);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool apply_output_configs(struct matched_output_config *configs,
|
static bool apply_resolved_output_configs(struct matched_output_config *configs,
|
||||||
size_t configs_len, bool test_only, bool degrade_to_off) {
|
size_t configs_len, bool test_only, bool degrade_to_off) {
|
||||||
struct wlr_backend_output_state *states = calloc(configs_len, sizeof(*states));
|
struct wlr_backend_output_state *states = calloc(configs_len, sizeof(*states));
|
||||||
if (!states) {
|
if (!states) {
|
||||||
|
@ -888,9 +875,8 @@ bool apply_output_configs(struct matched_output_config *configs,
|
||||||
backend_state->output = cfg->output->wlr_output;
|
backend_state->output = cfg->output->wlr_output;
|
||||||
wlr_output_state_init(&backend_state->base);
|
wlr_output_state_init(&backend_state->base);
|
||||||
|
|
||||||
sway_log(SWAY_DEBUG, "Preparing config for %s",
|
|
||||||
cfg->output->wlr_output->name);
|
|
||||||
queue_output_config(cfg->config, cfg->output, &backend_state->base);
|
queue_output_config(cfg->config, cfg->output, &backend_state->base);
|
||||||
|
dump_output_state(cfg->output->wlr_output, &backend_state->base);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_output_swapchain_manager swapchain_mgr;
|
struct wlr_output_swapchain_manager swapchain_mgr;
|
||||||
|
@ -952,6 +938,19 @@ bool apply_output_configs(struct matched_output_config *configs,
|
||||||
finalize_output_config(cfg->config, cfg->output);
|
finalize_output_config(cfg->config, cfg->output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Output layout being applied in finalize_output_config can shift outputs
|
||||||
|
// around, so we do a second pass to update positions and arrange.
|
||||||
|
for (size_t idx = 0; idx < configs_len; idx++) {
|
||||||
|
struct matched_output_config *cfg = &configs[idx];
|
||||||
|
output_update_position(cfg->output);
|
||||||
|
arrange_layers(cfg->output);
|
||||||
|
}
|
||||||
|
|
||||||
|
arrange_root();
|
||||||
|
arrange_locks();
|
||||||
|
update_output_manager_config(&server);
|
||||||
|
transaction_commit_dirty();
|
||||||
|
|
||||||
out:
|
out:
|
||||||
wlr_output_swapchain_manager_finish(&swapchain_mgr);
|
wlr_output_swapchain_manager_finish(&swapchain_mgr);
|
||||||
for (size_t idx = 0; idx < configs_len; idx++) {
|
for (size_t idx = 0; idx < configs_len; idx++) {
|
||||||
|
@ -976,11 +975,12 @@ out:
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_all_output_configs(void) {
|
bool apply_output_configs(struct output_config **ocs, size_t ocs_len,
|
||||||
|
bool test_only, bool degrade_to_off) {
|
||||||
size_t configs_len = wl_list_length(&root->all_outputs);
|
size_t configs_len = wl_list_length(&root->all_outputs);
|
||||||
struct matched_output_config *configs = calloc(configs_len, sizeof(*configs));
|
struct matched_output_config *configs = calloc(configs_len, sizeof(*configs));
|
||||||
if (!configs) {
|
if (!configs) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int config_idx = 0;
|
int config_idx = 0;
|
||||||
|
@ -993,16 +993,22 @@ void apply_all_output_configs(void) {
|
||||||
|
|
||||||
struct matched_output_config *config = &configs[config_idx++];
|
struct matched_output_config *config = &configs[config_idx++];
|
||||||
config->output = sway_output;
|
config->output = sway_output;
|
||||||
config->config = find_output_config(sway_output);
|
config->config = find_output_config_from_list(ocs, ocs_len, sway_output);
|
||||||
}
|
}
|
||||||
|
|
||||||
sort_output_configs_by_priority(configs, configs_len);
|
sort_output_configs_by_priority(configs, configs_len);
|
||||||
apply_output_configs(configs, configs_len, false, true);
|
bool ok = apply_resolved_output_configs(configs, configs_len, test_only, degrade_to_off);
|
||||||
for (size_t idx = 0; idx < configs_len; idx++) {
|
for (size_t idx = 0; idx < configs_len; idx++) {
|
||||||
struct matched_output_config *cfg = &configs[idx];
|
struct matched_output_config *cfg = &configs[idx];
|
||||||
free_output_config(cfg->config);
|
free_output_config(cfg->config);
|
||||||
}
|
}
|
||||||
free(configs);
|
free(configs);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_stored_output_configs(void) {
|
||||||
|
apply_output_configs((struct output_config **)config->output_configs->items,
|
||||||
|
config->output_configs->length, false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_output_config(struct output_config *oc) {
|
void free_output_config(struct output_config *oc) {
|
||||||
|
@ -1012,6 +1018,7 @@ void free_output_config(struct output_config *oc) {
|
||||||
free(oc->name);
|
free(oc->name);
|
||||||
free(oc->background);
|
free(oc->background);
|
||||||
free(oc->background_option);
|
free(oc->background_option);
|
||||||
|
free(oc->background_fallback);
|
||||||
wlr_color_transform_unref(oc->color_transform);
|
wlr_color_transform_unref(oc->color_transform);
|
||||||
free(oc);
|
free(oc);
|
||||||
}
|
}
|
||||||
|
@ -1054,41 +1061,28 @@ static bool _spawn_swaybg(char **command) {
|
||||||
return false;
|
return false;
|
||||||
} else if (pid == 0) {
|
} else if (pid == 0) {
|
||||||
restore_nofile_limit();
|
restore_nofile_limit();
|
||||||
|
restore_signals();
|
||||||
pid = fork();
|
if (!sway_set_cloexec(sockets[1], false)) {
|
||||||
if (pid < 0) {
|
|
||||||
sway_log_errno(SWAY_ERROR, "fork failed");
|
|
||||||
_exit(EXIT_FAILURE);
|
|
||||||
} else if (pid == 0) {
|
|
||||||
if (!sway_set_cloexec(sockets[1], false)) {
|
|
||||||
_exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
char wayland_socket_str[16];
|
|
||||||
snprintf(wayland_socket_str, sizeof(wayland_socket_str),
|
|
||||||
"%d", sockets[1]);
|
|
||||||
setenv("WAYLAND_SOCKET", wayland_socket_str, true);
|
|
||||||
|
|
||||||
execvp(command[0], command);
|
|
||||||
sway_log_errno(SWAY_ERROR, "failed to execute '%s' "
|
|
||||||
"(background configuration probably not applied)",
|
|
||||||
command[0]);
|
|
||||||
_exit(EXIT_FAILURE);
|
_exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
_exit(EXIT_SUCCESS);
|
|
||||||
|
char wayland_socket_str[16];
|
||||||
|
snprintf(wayland_socket_str, sizeof(wayland_socket_str),
|
||||||
|
"%d", sockets[1]);
|
||||||
|
setenv("WAYLAND_SOCKET", wayland_socket_str, true);
|
||||||
|
|
||||||
|
execvp(command[0], command);
|
||||||
|
sway_log_errno(SWAY_ERROR, "failed to execute '%s' "
|
||||||
|
"(background configuration probably not applied)",
|
||||||
|
command[0]);
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (close(sockets[1]) != 0) {
|
if (close(sockets[1]) != 0) {
|
||||||
sway_log_errno(SWAY_ERROR, "close failed");
|
sway_log_errno(SWAY_ERROR, "close failed");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int fork_status = 0;
|
return true;
|
||||||
if (waitpid(pid, &fork_status, 0) < 0) {
|
|
||||||
sway_log_errno(SWAY_ERROR, "waitpid failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return WIFEXITED(fork_status) && WEXITSTATUS(fork_status) == EXIT_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool spawn_swaybg(void) {
|
bool spawn_swaybg(void) {
|
||||||
|
|
|
@ -34,7 +34,10 @@ bool criteria_is_empty(struct criteria *criteria) {
|
||||||
&& !criteria->tiling
|
&& !criteria->tiling
|
||||||
&& !criteria->urgent
|
&& !criteria->urgent
|
||||||
&& !criteria->workspace
|
&& !criteria->workspace
|
||||||
&& !criteria->pid;
|
&& !criteria->pid
|
||||||
|
&& !criteria->sandbox_engine
|
||||||
|
&& !criteria->sandbox_app_id
|
||||||
|
&& !criteria->sandbox_instance_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The error pointer is used for parsing functions, and saves having to pass it
|
// The error pointer is used for parsing functions, and saves having to pass it
|
||||||
|
@ -98,6 +101,9 @@ void criteria_destroy(struct criteria *criteria) {
|
||||||
#endif
|
#endif
|
||||||
pattern_destroy(criteria->con_mark);
|
pattern_destroy(criteria->con_mark);
|
||||||
pattern_destroy(criteria->workspace);
|
pattern_destroy(criteria->workspace);
|
||||||
|
pattern_destroy(criteria->sandbox_engine);
|
||||||
|
pattern_destroy(criteria->sandbox_app_id);
|
||||||
|
pattern_destroy(criteria->sandbox_instance_id);
|
||||||
free(criteria->target);
|
free(criteria->target);
|
||||||
free(criteria->cmdlist);
|
free(criteria->cmdlist);
|
||||||
free(criteria->raw);
|
free(criteria->raw);
|
||||||
|
@ -248,6 +254,66 @@ static bool criteria_matches_view(struct criteria *criteria,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (criteria->sandbox_engine) {
|
||||||
|
const char *sandbox_engine = view_get_sandbox_engine(view);
|
||||||
|
if (!sandbox_engine) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (criteria->sandbox_engine->match_type) {
|
||||||
|
case PATTERN_FOCUSED:
|
||||||
|
if (focused && lenient_strcmp(sandbox_engine, view_get_sandbox_engine(focused))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PATTERN_PCRE2:
|
||||||
|
if (regex_cmp(sandbox_engine, criteria->sandbox_engine->regex) < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (criteria->sandbox_app_id) {
|
||||||
|
const char *sandbox_app_id = view_get_sandbox_app_id(view);
|
||||||
|
if (!sandbox_app_id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (criteria->sandbox_app_id->match_type) {
|
||||||
|
case PATTERN_FOCUSED:
|
||||||
|
if (focused && lenient_strcmp(sandbox_app_id, view_get_sandbox_app_id(focused))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PATTERN_PCRE2:
|
||||||
|
if (regex_cmp(sandbox_app_id, criteria->sandbox_app_id->regex) < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (criteria->sandbox_instance_id) {
|
||||||
|
const char *sandbox_instance_id = view_get_sandbox_instance_id(view);
|
||||||
|
if (!sandbox_instance_id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (criteria->sandbox_instance_id->match_type) {
|
||||||
|
case PATTERN_FOCUSED:
|
||||||
|
if (focused && lenient_strcmp(sandbox_instance_id, view_get_sandbox_instance_id(focused))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case PATTERN_PCRE2:
|
||||||
|
if (regex_cmp(sandbox_instance_id, criteria->sandbox_instance_id->regex) < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!criteria_matches_container(criteria, view->container)) {
|
if (!criteria_matches_container(criteria, view->container)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -475,6 +541,9 @@ enum criteria_token {
|
||||||
T_URGENT,
|
T_URGENT,
|
||||||
T_WORKSPACE,
|
T_WORKSPACE,
|
||||||
T_PID,
|
T_PID,
|
||||||
|
T_SANDBOX_ENGINE,
|
||||||
|
T_SANDBOX_APP_ID,
|
||||||
|
T_SANDBOX_INSTANCE_ID,
|
||||||
|
|
||||||
T_INVALID,
|
T_INVALID,
|
||||||
};
|
};
|
||||||
|
@ -514,6 +583,12 @@ static enum criteria_token token_from_name(char *name) {
|
||||||
return T_FLOATING;
|
return T_FLOATING;
|
||||||
} else if (strcmp(name, "pid") == 0) {
|
} else if (strcmp(name, "pid") == 0) {
|
||||||
return T_PID;
|
return T_PID;
|
||||||
|
} else if (strcmp(name, "sandbox_engine") == 0) {
|
||||||
|
return T_SANDBOX_ENGINE;
|
||||||
|
} else if (strcmp(name, "sandbox_app_id") == 0) {
|
||||||
|
return T_SANDBOX_APP_ID;
|
||||||
|
} else if (strcmp(name, "sandbox_instance_id") == 0) {
|
||||||
|
return T_SANDBOX_INSTANCE_ID;
|
||||||
}
|
}
|
||||||
return T_INVALID;
|
return T_INVALID;
|
||||||
}
|
}
|
||||||
|
@ -555,8 +630,7 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
|
||||||
if (strcmp(value, "__focused__") == 0) {
|
if (strcmp(value, "__focused__") == 0) {
|
||||||
struct sway_seat *seat = input_manager_current_seat();
|
struct sway_seat *seat = input_manager_current_seat();
|
||||||
struct sway_container *focus = seat_get_focused_container(seat);
|
struct sway_container *focus = seat_get_focused_container(seat);
|
||||||
struct sway_view *view = focus ? focus->view : NULL;
|
criteria->con_id = focus ? focus->node.id : 0;
|
||||||
criteria->con_id = view ? view->container->node.id : 0;
|
|
||||||
} else {
|
} else {
|
||||||
criteria->con_id = strtoul(value, &endptr, 10);
|
criteria->con_id = strtoul(value, &endptr, 10);
|
||||||
if (*endptr != 0) {
|
if (*endptr != 0) {
|
||||||
|
@ -617,6 +691,15 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
|
||||||
error = strdup("The value for 'pid' should be numeric");
|
error = strdup("The value for 'pid' should be numeric");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case T_SANDBOX_ENGINE:
|
||||||
|
pattern_create(&criteria->sandbox_engine, value);
|
||||||
|
break;
|
||||||
|
case T_SANDBOX_APP_ID:
|
||||||
|
pattern_create(&criteria->sandbox_app_id, value);
|
||||||
|
break;
|
||||||
|
case T_SANDBOX_INSTANCE_ID:
|
||||||
|
pattern_create(&criteria->sandbox_instance_id, value);
|
||||||
|
break;
|
||||||
case T_INVALID:
|
case T_INVALID:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
|
||||||
}
|
}
|
||||||
|
|
||||||
static void arrange_surface(struct sway_output *output, const struct wlr_box *full_area,
|
static void arrange_surface(struct sway_output *output, const struct wlr_box *full_area,
|
||||||
struct wlr_box *usable_area, struct wlr_scene_tree *tree) {
|
struct wlr_box *usable_area, struct wlr_scene_tree *tree, bool exclusive) {
|
||||||
struct wlr_scene_node *node;
|
struct wlr_scene_node *node;
|
||||||
wl_list_for_each(node, &tree->children, link) {
|
wl_list_for_each(node, &tree->children, link) {
|
||||||
struct sway_layer_surface *surface = scene_descriptor_try_get(node,
|
struct sway_layer_surface *surface = scene_descriptor_try_get(node,
|
||||||
|
@ -68,6 +68,10 @@ static void arrange_surface(struct sway_output *output, const struct wlr_box *fu
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((surface->scene->layer_surface->current.exclusive_zone > 0) != exclusive) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
wlr_scene_layer_surface_v1_configure(surface->scene, full_area, usable_area);
|
wlr_scene_layer_surface_v1_configure(surface->scene, full_area, usable_area);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -78,10 +82,15 @@ void arrange_layers(struct sway_output *output) {
|
||||||
&usable_area.width, &usable_area.height);
|
&usable_area.width, &usable_area.height);
|
||||||
const struct wlr_box full_area = usable_area;
|
const struct wlr_box full_area = usable_area;
|
||||||
|
|
||||||
arrange_surface(output, &full_area, &usable_area, output->layers.shell_background);
|
arrange_surface(output, &full_area, &usable_area, output->layers.shell_overlay, true);
|
||||||
arrange_surface(output, &full_area, &usable_area, output->layers.shell_bottom);
|
arrange_surface(output, &full_area, &usable_area, output->layers.shell_top, true);
|
||||||
arrange_surface(output, &full_area, &usable_area, output->layers.shell_top);
|
arrange_surface(output, &full_area, &usable_area, output->layers.shell_bottom, true);
|
||||||
arrange_surface(output, &full_area, &usable_area, output->layers.shell_overlay);
|
arrange_surface(output, &full_area, &usable_area, output->layers.shell_background, true);
|
||||||
|
|
||||||
|
arrange_surface(output, &full_area, &usable_area, output->layers.shell_overlay, false);
|
||||||
|
arrange_surface(output, &full_area, &usable_area, output->layers.shell_top, false);
|
||||||
|
arrange_surface(output, &full_area, &usable_area, output->layers.shell_bottom, false);
|
||||||
|
arrange_surface(output, &full_area, &usable_area, output->layers.shell_background, false);
|
||||||
|
|
||||||
if (!wlr_box_equal(&usable_area, &output->usable_area)) {
|
if (!wlr_box_equal(&usable_area, &output->usable_area)) {
|
||||||
sway_log(SWAY_DEBUG, "Usable area changed, rearranging output");
|
sway_log(SWAY_DEBUG, "Usable area changed, rearranging output");
|
||||||
|
@ -90,6 +99,43 @@ void arrange_layers(struct sway_output *output) {
|
||||||
} else {
|
} else {
|
||||||
arrange_popups(root->layers.popup);
|
arrange_popups(root->layers.popup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find topmost keyboard interactive layer, if such a layer exists
|
||||||
|
struct wlr_scene_tree *layers_above_shell[] = {
|
||||||
|
output->layers.shell_overlay,
|
||||||
|
output->layers.shell_top,
|
||||||
|
};
|
||||||
|
size_t nlayers = sizeof(layers_above_shell) / sizeof(layers_above_shell[0]);
|
||||||
|
struct wlr_scene_node *node;
|
||||||
|
struct sway_layer_surface *topmost = NULL;
|
||||||
|
for (size_t i = 0; i < nlayers; ++i) {
|
||||||
|
wl_list_for_each_reverse(node,
|
||||||
|
&layers_above_shell[i]->children, link) {
|
||||||
|
struct sway_layer_surface *surface = scene_descriptor_try_get(node,
|
||||||
|
SWAY_SCENE_DESC_LAYER_SHELL);
|
||||||
|
if (surface && surface->layer_surface->current.keyboard_interactive
|
||||||
|
== ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE &&
|
||||||
|
surface->layer_surface->surface->mapped) {
|
||||||
|
topmost = surface;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (topmost != NULL) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sway_seat *seat;
|
||||||
|
wl_list_for_each(seat, &server.input->seats, link) {
|
||||||
|
seat->has_exclusive_layer = false;
|
||||||
|
if (topmost != NULL) {
|
||||||
|
seat_set_focus_layer(seat, topmost->layer_surface);
|
||||||
|
} else if (seat->focused_layer &&
|
||||||
|
seat->focused_layer->current.keyboard_interactive
|
||||||
|
!= ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) {
|
||||||
|
seat_set_focus_layer(seat, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct wlr_scene_tree *sway_layer_get_scene(struct sway_output *output,
|
static struct wlr_scene_tree *sway_layer_get_scene(struct sway_output *output,
|
||||||
|
@ -210,6 +256,7 @@ static void handle_node_destroy(struct wl_listener *listener, void *data) {
|
||||||
wl_list_remove(&layer->unmap.link);
|
wl_list_remove(&layer->unmap.link);
|
||||||
wl_list_remove(&layer->surface_commit.link);
|
wl_list_remove(&layer->surface_commit.link);
|
||||||
wl_list_remove(&layer->node_destroy.link);
|
wl_list_remove(&layer->node_destroy.link);
|
||||||
|
wl_list_remove(&layer->new_popup.link);
|
||||||
wl_list_remove(&layer->output_destroy.link);
|
wl_list_remove(&layer->output_destroy.link);
|
||||||
|
|
||||||
layer->layer_surface->data = NULL;
|
layer->layer_surface->data = NULL;
|
||||||
|
|
|
@ -8,8 +8,8 @@
|
||||||
#include <wlr/render/swapchain.h>
|
#include <wlr/render/swapchain.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_alpha_modifier_v1.h>
|
||||||
#include <wlr/types/wlr_gamma_control_v1.h>
|
#include <wlr/types/wlr_gamma_control_v1.h>
|
||||||
#include <wlr/types/wlr_matrix.h>
|
|
||||||
#include <wlr/types/wlr_output_layout.h>
|
#include <wlr/types/wlr_output_layout.h>
|
||||||
#include <wlr/types/wlr_output_management_v1.h>
|
#include <wlr/types/wlr_output_management_v1.h>
|
||||||
#include <wlr/types/wlr_output_power_management_v1.h>
|
#include <wlr/types/wlr_output_power_management_v1.h>
|
||||||
|
@ -187,8 +187,8 @@ static enum wlr_scale_filter_mode get_scale_filter(struct sway_output *output,
|
||||||
struct wlr_scene_buffer *buffer) {
|
struct wlr_scene_buffer *buffer) {
|
||||||
// if we are scaling down, we should always choose linear
|
// if we are scaling down, we should always choose linear
|
||||||
if (buffer->dst_width > 0 && buffer->dst_height > 0 && (
|
if (buffer->dst_width > 0 && buffer->dst_height > 0 && (
|
||||||
buffer->dst_width < buffer->buffer_width ||
|
buffer->dst_width < buffer->WLR_PRIVATE.buffer_width ||
|
||||||
buffer->dst_height < buffer->buffer_height)) {
|
buffer->dst_height < buffer->WLR_PRIVATE.buffer_height)) {
|
||||||
return WLR_SCALE_FILTER_BILINEAR;
|
return WLR_SCALE_FILTER_BILINEAR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,7 +202,7 @@ static enum wlr_scale_filter_mode get_scale_filter(struct sway_output *output,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void output_configure_scene(struct sway_output *output,
|
void output_configure_scene(struct sway_output *output,
|
||||||
struct wlr_scene_node *node, float opacity) {
|
struct wlr_scene_node *node, float opacity) {
|
||||||
if (!node->enabled) {
|
if (!node->enabled) {
|
||||||
return;
|
return;
|
||||||
|
@ -216,11 +216,22 @@ static void output_configure_scene(struct sway_output *output,
|
||||||
|
|
||||||
if (node->type == WLR_SCENE_NODE_BUFFER) {
|
if (node->type == WLR_SCENE_NODE_BUFFER) {
|
||||||
struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node);
|
struct wlr_scene_buffer *buffer = wlr_scene_buffer_from_node(node);
|
||||||
|
struct wlr_scene_surface *surface = wlr_scene_surface_try_from_buffer(buffer);
|
||||||
|
|
||||||
|
if (surface) {
|
||||||
|
const struct wlr_alpha_modifier_surface_v1_state *alpha_modifier_state =
|
||||||
|
wlr_alpha_modifier_v1_get_surface_state(surface->surface);
|
||||||
|
if (alpha_modifier_state != NULL) {
|
||||||
|
opacity *= (float)alpha_modifier_state->multiplier;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// hack: don't call the scene setter because that will damage all outputs
|
// hack: don't call the scene setter because that will damage all outputs
|
||||||
// We don't want to damage outputs that aren't our current output that
|
// We don't want to damage outputs that aren't our current output that
|
||||||
// we're configuring
|
// we're configuring
|
||||||
buffer->filter_mode = get_scale_filter(output, buffer);
|
if (output) {
|
||||||
|
buffer->filter_mode = get_scale_filter(output, buffer);
|
||||||
|
}
|
||||||
|
|
||||||
wlr_scene_buffer_set_opacity(buffer, opacity);
|
wlr_scene_buffer_set_opacity(buffer, opacity);
|
||||||
} else if (node->type == WLR_SCENE_NODE_TREE) {
|
} else if (node->type == WLR_SCENE_NODE_TREE) {
|
||||||
|
@ -232,40 +243,56 @@ static void output_configure_scene(struct sway_output *output,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool output_can_tear(struct sway_output *output) {
|
||||||
|
struct sway_workspace *workspace = output->current.active_workspace;
|
||||||
|
if (!workspace) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sway_container *fullscreen_con = root->fullscreen_global;
|
||||||
|
if (!fullscreen_con) {
|
||||||
|
fullscreen_con = workspace->current.fullscreen;
|
||||||
|
}
|
||||||
|
if (fullscreen_con && fullscreen_con->view) {
|
||||||
|
return (output->allow_tearing && view_can_tear(fullscreen_con->view));
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static int output_repaint_timer_handler(void *data) {
|
static int output_repaint_timer_handler(void *data) {
|
||||||
struct sway_output *output = data;
|
struct sway_output *output = data;
|
||||||
|
|
||||||
if (!output->enabled) {
|
output->wlr_output->frame_pending = false;
|
||||||
|
if (!output->wlr_output->enabled) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
output->wlr_output->frame_pending = false;
|
|
||||||
|
|
||||||
output_configure_scene(output, &root->root_scene->tree.node, 1.0f);
|
output_configure_scene(output, &root->root_scene->tree.node, 1.0f);
|
||||||
|
|
||||||
struct wlr_scene_output_state_options opts = {
|
struct wlr_scene_output_state_options opts = {
|
||||||
.color_transform = output->color_transform,
|
.color_transform = output->color_transform,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_output_state pending;
|
struct wlr_scene_output *scene_output = output->scene_output;
|
||||||
wlr_output_state_init(&pending);
|
if (!wlr_scene_output_needs_frame(scene_output)) {
|
||||||
if (!wlr_scene_output_build_state(output->scene_output, &pending, &opts)) {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (output->gamma_lut_changed) {
|
struct wlr_output_state pending;
|
||||||
output->gamma_lut_changed = false;
|
wlr_output_state_init(&pending);
|
||||||
struct wlr_gamma_control_v1 *gamma_control =
|
if (!wlr_scene_output_build_state(output->scene_output, &pending, &opts)) {
|
||||||
wlr_gamma_control_manager_v1_get_control(
|
wlr_output_state_finish(&pending);
|
||||||
server.gamma_control_manager_v1, output->wlr_output);
|
return 0;
|
||||||
if (!wlr_gamma_control_v1_apply(gamma_control, &pending)) {
|
}
|
||||||
wlr_output_state_finish(&pending);
|
|
||||||
return 0;
|
if (output_can_tear(output)) {
|
||||||
}
|
pending.tearing_page_flip = true;
|
||||||
|
|
||||||
if (!wlr_output_test_state(output->wlr_output, &pending)) {
|
if (!wlr_output_test_state(output->wlr_output, &pending)) {
|
||||||
wlr_gamma_control_v1_send_failed_and_destroy(gamma_control);
|
sway_log(SWAY_DEBUG, "Output test failed on '%s', retrying without tearing page-flip",
|
||||||
wlr_output_state_set_gamma_lut(&pending, 0, NULL, NULL, NULL);
|
output->wlr_output->name);
|
||||||
|
pending.tearing_page_flip = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -340,7 +367,7 @@ static void handle_frame(struct wl_listener *listener, void *user_data) {
|
||||||
wlr_scene_output_for_each_buffer(output->scene_output, send_frame_done_iterator, &data);
|
wlr_scene_output_for_each_buffer(output->scene_output, send_frame_done_iterator, &data);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_output_manager_config(struct sway_server *server) {
|
void update_output_manager_config(struct sway_server *server) {
|
||||||
struct wlr_output_configuration_v1 *config =
|
struct wlr_output_configuration_v1 *config =
|
||||||
wlr_output_configuration_v1_create();
|
wlr_output_configuration_v1_create();
|
||||||
|
|
||||||
|
@ -370,24 +397,31 @@ static int timer_modeset_handle(void *data) {
|
||||||
wl_event_source_remove(server->delayed_modeset);
|
wl_event_source_remove(server->delayed_modeset);
|
||||||
server->delayed_modeset = NULL;
|
server->delayed_modeset = NULL;
|
||||||
|
|
||||||
apply_all_output_configs();
|
apply_stored_output_configs();
|
||||||
transaction_commit_dirty();
|
|
||||||
update_output_manager_config(server);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void request_modeset(struct sway_server *server) {
|
void request_modeset(void) {
|
||||||
if (server->delayed_modeset == NULL) {
|
if (server.delayed_modeset == NULL) {
|
||||||
server->delayed_modeset = wl_event_loop_add_timer(server->wl_event_loop,
|
server.delayed_modeset = wl_event_loop_add_timer(server.wl_event_loop,
|
||||||
timer_modeset_handle, server);
|
timer_modeset_handle, &server);
|
||||||
wl_event_source_timer_update(server->delayed_modeset, 10);
|
wl_event_source_timer_update(server.delayed_modeset, 10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void begin_destroy(struct sway_output *output) {
|
bool modeset_is_pending(void) {
|
||||||
struct sway_server *server = output->server;
|
return server.delayed_modeset != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void force_modeset(void) {
|
||||||
|
if (server.delayed_modeset != NULL) {
|
||||||
|
wl_event_source_remove(server.delayed_modeset);
|
||||||
|
server.delayed_modeset = NULL;
|
||||||
|
}
|
||||||
|
apply_stored_output_configs();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void begin_destroy(struct sway_output *output) {
|
||||||
if (output->enabled) {
|
if (output->enabled) {
|
||||||
output_disable(output);
|
output_disable(output);
|
||||||
}
|
}
|
||||||
|
@ -398,7 +432,6 @@ static void begin_destroy(struct sway_output *output) {
|
||||||
|
|
||||||
wl_list_remove(&output->layout_destroy.link);
|
wl_list_remove(&output->layout_destroy.link);
|
||||||
wl_list_remove(&output->destroy.link);
|
wl_list_remove(&output->destroy.link);
|
||||||
wl_list_remove(&output->commit.link);
|
|
||||||
wl_list_remove(&output->present.link);
|
wl_list_remove(&output->present.link);
|
||||||
wl_list_remove(&output->frame.link);
|
wl_list_remove(&output->frame.link);
|
||||||
wl_list_remove(&output->request_state.link);
|
wl_list_remove(&output->request_state.link);
|
||||||
|
@ -408,7 +441,10 @@ static void begin_destroy(struct sway_output *output) {
|
||||||
output->wlr_output->data = NULL;
|
output->wlr_output->data = NULL;
|
||||||
output->wlr_output = NULL;
|
output->wlr_output = NULL;
|
||||||
|
|
||||||
request_modeset(server);
|
wl_event_source_remove(output->repaint_timer);
|
||||||
|
output->repaint_timer = NULL;
|
||||||
|
|
||||||
|
request_modeset();
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_destroy(struct wl_listener *listener, void *data) {
|
static void handle_destroy(struct wl_listener *listener, void *data) {
|
||||||
|
@ -421,31 +457,6 @@ static void handle_layout_destroy(struct wl_listener *listener, void *data) {
|
||||||
begin_destroy(output);
|
begin_destroy(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_commit(struct wl_listener *listener, void *data) {
|
|
||||||
struct sway_output *output = wl_container_of(listener, output, commit);
|
|
||||||
struct wlr_output_event_commit *event = data;
|
|
||||||
|
|
||||||
if (!output->enabled) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (event->state->committed & (
|
|
||||||
WLR_OUTPUT_STATE_MODE |
|
|
||||||
WLR_OUTPUT_STATE_TRANSFORM |
|
|
||||||
WLR_OUTPUT_STATE_SCALE)) {
|
|
||||||
arrange_layers(output);
|
|
||||||
arrange_output(output);
|
|
||||||
transaction_commit_dirty();
|
|
||||||
|
|
||||||
update_output_manager_config(output->server);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Next time the output is enabled, try to re-apply the gamma LUT
|
|
||||||
if ((event->state->committed & WLR_OUTPUT_STATE_ENABLED) && !output->wlr_output->enabled) {
|
|
||||||
output->gamma_lut_changed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void handle_present(struct wl_listener *listener, void *data) {
|
static void handle_present(struct wl_listener *listener, void *data) {
|
||||||
struct sway_output *output = wl_container_of(listener, output, present);
|
struct sway_output *output = wl_container_of(listener, output, present);
|
||||||
struct wlr_output_event_present *output_event = data;
|
struct wlr_output_event_present *output_event = data;
|
||||||
|
@ -454,7 +465,7 @@ static void handle_present(struct wl_listener *listener, void *data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
output->last_presentation = *output_event->when;
|
output->last_presentation = output_event->when;
|
||||||
output->refresh_nsec = output_event->refresh;
|
output->refresh_nsec = output_event->refresh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -462,7 +473,44 @@ static void handle_request_state(struct wl_listener *listener, void *data) {
|
||||||
struct sway_output *output =
|
struct sway_output *output =
|
||||||
wl_container_of(listener, output, request_state);
|
wl_container_of(listener, output, request_state);
|
||||||
const struct wlr_output_event_request_state *event = data;
|
const struct wlr_output_event_request_state *event = data;
|
||||||
wlr_output_commit_state(output->wlr_output, event->state);
|
const struct wlr_output_state *state = event->state;
|
||||||
|
|
||||||
|
// Store the requested changes so that the active configuration is
|
||||||
|
// consistent with the current state, and to avoid duplicate logic to apply
|
||||||
|
// the changes.
|
||||||
|
struct output_config *oc = new_output_config(output->wlr_output->name);
|
||||||
|
if (!oc) {
|
||||||
|
sway_log(SWAY_ERROR, "Allocation failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int committed = state->committed;
|
||||||
|
if (committed & WLR_OUTPUT_STATE_MODE) {
|
||||||
|
if (state->mode != NULL) {
|
||||||
|
oc->width = state->mode->width;
|
||||||
|
oc->height = state->mode->height;
|
||||||
|
oc->refresh_rate = state->mode->refresh / 1000.f;
|
||||||
|
} else {
|
||||||
|
oc->width = state->custom_mode.width;
|
||||||
|
oc->height = state->custom_mode.height;
|
||||||
|
oc->refresh_rate = state->custom_mode.refresh / 1000.f;
|
||||||
|
}
|
||||||
|
committed &= ~WLR_OUTPUT_STATE_MODE;
|
||||||
|
}
|
||||||
|
if (committed & WLR_OUTPUT_STATE_SCALE) {
|
||||||
|
oc->scale = state->scale;
|
||||||
|
committed &= ~WLR_OUTPUT_STATE_SCALE;
|
||||||
|
}
|
||||||
|
if (committed & WLR_OUTPUT_STATE_TRANSFORM) {
|
||||||
|
oc->transform = state->transform;
|
||||||
|
committed &= ~WLR_OUTPUT_STATE_TRANSFORM;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We do not expect or support any other changes here
|
||||||
|
assert(committed == 0);
|
||||||
|
store_output_config(oc);
|
||||||
|
|
||||||
|
force_modeset();
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int last_headless_num = 0;
|
static unsigned int last_headless_num = 0;
|
||||||
|
@ -526,8 +574,6 @@ void handle_new_output(struct wl_listener *listener, void *data) {
|
||||||
output->layout_destroy.notify = handle_layout_destroy;
|
output->layout_destroy.notify = handle_layout_destroy;
|
||||||
wl_signal_add(&wlr_output->events.destroy, &output->destroy);
|
wl_signal_add(&wlr_output->events.destroy, &output->destroy);
|
||||||
output->destroy.notify = handle_destroy;
|
output->destroy.notify = handle_destroy;
|
||||||
wl_signal_add(&wlr_output->events.commit, &output->commit);
|
|
||||||
output->commit.notify = handle_commit;
|
|
||||||
wl_signal_add(&wlr_output->events.present, &output->present);
|
wl_signal_add(&wlr_output->events.present, &output->present);
|
||||||
output->present.notify = handle_present;
|
output->present.notify = handle_present;
|
||||||
wl_signal_add(&wlr_output->events.frame, &output->frame);
|
wl_signal_add(&wlr_output->events.frame, &output->frame);
|
||||||
|
@ -542,35 +588,16 @@ void handle_new_output(struct wl_listener *listener, void *data) {
|
||||||
sway_session_lock_add_output(server->session_lock.lock, output);
|
sway_session_lock_add_output(server->session_lock.lock, output);
|
||||||
}
|
}
|
||||||
|
|
||||||
request_modeset(server);
|
request_modeset();
|
||||||
}
|
|
||||||
|
|
||||||
void handle_output_layout_change(struct wl_listener *listener,
|
|
||||||
void *data) {
|
|
||||||
struct sway_server *server =
|
|
||||||
wl_container_of(listener, server, output_layout_change);
|
|
||||||
update_output_manager_config(server);
|
|
||||||
}
|
|
||||||
|
|
||||||
void handle_gamma_control_set_gamma(struct wl_listener *listener, void *data) {
|
|
||||||
struct sway_server *server =
|
|
||||||
wl_container_of(listener, server, gamma_control_set_gamma);
|
|
||||||
const struct wlr_gamma_control_manager_v1_set_gamma_event *event = data;
|
|
||||||
|
|
||||||
struct sway_output *output = event->output->data;
|
|
||||||
|
|
||||||
if(!output) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
output->gamma_lut_changed = true;
|
|
||||||
wlr_output_schedule_frame(output->wlr_output);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct output_config *output_config_for_config_head(
|
static struct output_config *output_config_for_config_head(
|
||||||
struct wlr_output_configuration_head_v1 *config_head,
|
struct wlr_output_configuration_head_v1 *config_head) {
|
||||||
struct sway_output *output) {
|
struct output_config *oc = new_output_config(config_head->state.output->name);
|
||||||
struct output_config *oc = new_output_config(output->wlr_output->name);
|
if (!oc) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
oc->enabled = config_head->state.enabled;
|
oc->enabled = config_head->state.enabled;
|
||||||
if (!oc->enabled) {
|
if (!oc->enabled) {
|
||||||
return oc;
|
return oc;
|
||||||
|
@ -596,71 +623,59 @@ static struct output_config *output_config_for_config_head(
|
||||||
}
|
}
|
||||||
|
|
||||||
static void output_manager_apply(struct sway_server *server,
|
static void output_manager_apply(struct sway_server *server,
|
||||||
struct wlr_output_configuration_v1 *config, bool test_only) {
|
struct wlr_output_configuration_v1 *cfg, bool test_only) {
|
||||||
size_t configs_len = wl_list_length(&root->all_outputs);
|
bool ok = false;
|
||||||
struct matched_output_config *configs = calloc(configs_len, sizeof(*configs));
|
size_t configs_len = config->output_configs->length + wl_list_length(&cfg->heads);
|
||||||
|
struct output_config **configs = calloc(configs_len, sizeof(*configs));
|
||||||
if (!configs) {
|
if (!configs) {
|
||||||
return;
|
sway_log(SWAY_ERROR, "Allocation failed");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
size_t start_new_configs = config->output_configs->length;
|
||||||
|
for (size_t idx = 0; idx < start_new_configs; idx++) {
|
||||||
|
configs[idx] = config->output_configs->items[idx];
|
||||||
}
|
}
|
||||||
|
|
||||||
int config_idx = 0;
|
size_t config_idx = start_new_configs;
|
||||||
struct sway_output *sway_output;
|
struct wlr_output_configuration_head_v1 *config_head;
|
||||||
wl_list_for_each(sway_output, &root->all_outputs, link) {
|
wl_list_for_each(config_head, &cfg->heads, link) {
|
||||||
if (sway_output == root->fallback_output) {
|
// Generate the configuration and store it as a temporary
|
||||||
configs_len--;
|
// config. We keep a record of it so we can remove it later.
|
||||||
continue;
|
struct output_config *oc = output_config_for_config_head(config_head);
|
||||||
}
|
if (!oc) {
|
||||||
|
sway_log(SWAY_ERROR, "Allocation failed");
|
||||||
struct matched_output_config *cfg = &configs[config_idx++];
|
goto error_config;
|
||||||
cfg->output = sway_output;
|
|
||||||
|
|
||||||
struct wlr_output_configuration_head_v1 *config_head;
|
|
||||||
wl_list_for_each(config_head, &config->heads, link) {
|
|
||||||
if (config_head->state.output == sway_output->wlr_output) {
|
|
||||||
cfg->config = output_config_for_config_head(config_head, sway_output);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!cfg->config) {
|
|
||||||
cfg->config = find_output_config(sway_output);
|
|
||||||
}
|
}
|
||||||
|
configs[config_idx++] = oc;
|
||||||
}
|
}
|
||||||
|
|
||||||
sort_output_configs_by_priority(configs, configs_len);
|
// Try to commit without degrade to off enabled. Note that this will fail
|
||||||
bool ok = apply_output_configs(configs, configs_len, test_only, false);
|
// if any output configured for enablement fails to be enabled, even if it
|
||||||
for (size_t idx = 0; idx < configs_len; idx++) {
|
// was not part of the config heads we were asked to configure.
|
||||||
struct matched_output_config *cfg = &configs[idx];
|
ok = apply_output_configs(configs, configs_len, test_only, false);
|
||||||
|
|
||||||
// Only store new configs for successful non-test commits. Old configs,
|
error_config:
|
||||||
// test-only and failed commits just get freed.
|
for (size_t idx = start_new_configs; idx < configs_len; idx++) {
|
||||||
bool store_config = false;
|
struct output_config *cfg = configs[idx];
|
||||||
if (!test_only && ok) {
|
if (!test_only && ok) {
|
||||||
struct wlr_output_configuration_head_v1 *config_head;
|
store_output_config(cfg);
|
||||||
wl_list_for_each(config_head, &config->heads, link) {
|
|
||||||
if (config_head->state.output == cfg->output->wlr_output) {
|
|
||||||
store_config = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (store_config) {
|
|
||||||
store_output_config(cfg->config);
|
|
||||||
} else {
|
} else {
|
||||||
free_output_config(cfg->config);
|
free_output_config(cfg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(configs);
|
free(configs);
|
||||||
|
|
||||||
|
error:
|
||||||
if (ok) {
|
if (ok) {
|
||||||
wlr_output_configuration_v1_send_succeeded(config);
|
wlr_output_configuration_v1_send_succeeded(cfg);
|
||||||
|
if (server->delayed_modeset != NULL) {
|
||||||
|
wl_event_source_remove(server->delayed_modeset);
|
||||||
|
server->delayed_modeset = NULL;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
wlr_output_configuration_v1_send_failed(config);
|
wlr_output_configuration_v1_send_failed(cfg);
|
||||||
}
|
|
||||||
wlr_output_configuration_v1_destroy(config);
|
|
||||||
|
|
||||||
if (!test_only) {
|
|
||||||
update_output_manager_config(server);
|
|
||||||
}
|
}
|
||||||
|
wlr_output_configuration_v1_destroy(cfg);
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_output_manager_apply(struct wl_listener *listener, void *data) {
|
void handle_output_manager_apply(struct wl_listener *listener, void *data) {
|
||||||
|
@ -685,6 +700,11 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener,
|
||||||
struct sway_output *output = event->output->data;
|
struct sway_output *output = event->output->data;
|
||||||
|
|
||||||
struct output_config *oc = new_output_config(output->wlr_output->name);
|
struct output_config *oc = new_output_config(output->wlr_output->name);
|
||||||
|
if (!oc) {
|
||||||
|
sway_log(SWAY_ERROR, "Allocation failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (event->mode) {
|
switch (event->mode) {
|
||||||
case ZWLR_OUTPUT_POWER_V1_MODE_OFF:
|
case ZWLR_OUTPUT_POWER_V1_MODE_OFF:
|
||||||
oc->power = 0;
|
oc->power = 0;
|
||||||
|
@ -694,5 +714,5 @@ void handle_output_power_manager_set_mode(struct wl_listener *listener,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
store_output_config(oc);
|
store_output_config(oc);
|
||||||
request_modeset(output->server);
|
request_modeset();
|
||||||
}
|
}
|
||||||
|
|
64
sway/desktop/tearing.c
Normal file
64
sway/desktop/tearing.c
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
#include <wayland-server-core.h>
|
||||||
|
#include <wlr/types/wlr_tearing_control_v1.h>
|
||||||
|
#include "sway/server.h"
|
||||||
|
#include "sway/tree/view.h"
|
||||||
|
#include "sway/output.h"
|
||||||
|
#include "log.h"
|
||||||
|
|
||||||
|
struct sway_tearing_controller {
|
||||||
|
struct wlr_tearing_control_v1 *tearing_control;
|
||||||
|
struct wl_listener set_hint;
|
||||||
|
struct wl_listener destroy;
|
||||||
|
|
||||||
|
struct wl_list link; // sway_server::tearing_controllers
|
||||||
|
};
|
||||||
|
|
||||||
|
static void handle_tearing_controller_set_hint(struct wl_listener *listener,
|
||||||
|
void *data) {
|
||||||
|
struct sway_tearing_controller *controller =
|
||||||
|
wl_container_of(listener, controller, set_hint);
|
||||||
|
|
||||||
|
struct sway_view *view = view_from_wlr_surface(
|
||||||
|
controller->tearing_control->surface);
|
||||||
|
if (view) {
|
||||||
|
view->tearing_hint = controller->tearing_control->current;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_tearing_controller_destroy(struct wl_listener *listener,
|
||||||
|
void *data) {
|
||||||
|
struct sway_tearing_controller *controller =
|
||||||
|
wl_container_of(listener, controller, destroy);
|
||||||
|
wl_list_remove(&controller->set_hint.link);
|
||||||
|
wl_list_remove(&controller->destroy.link);
|
||||||
|
wl_list_remove(&controller->link);
|
||||||
|
free(controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
void handle_new_tearing_hint(struct wl_listener *listener,
|
||||||
|
void *data) {
|
||||||
|
struct sway_server *server =
|
||||||
|
wl_container_of(listener, server, tearing_control_new_object);
|
||||||
|
struct wlr_tearing_control_v1 *tearing_control = data;
|
||||||
|
|
||||||
|
enum wp_tearing_control_v1_presentation_hint hint =
|
||||||
|
wlr_tearing_control_manager_v1_surface_hint_from_surface(
|
||||||
|
server->tearing_control_v1, tearing_control->surface);
|
||||||
|
sway_log(SWAY_DEBUG, "New presentation hint %d received for surface %p",
|
||||||
|
hint, tearing_control->surface);
|
||||||
|
|
||||||
|
struct sway_tearing_controller *controller =
|
||||||
|
calloc(1, sizeof(struct sway_tearing_controller));
|
||||||
|
if (!controller) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
controller->tearing_control = tearing_control;
|
||||||
|
controller->set_hint.notify = handle_tearing_controller_set_hint;
|
||||||
|
wl_signal_add(&tearing_control->events.set_hint, &controller->set_hint);
|
||||||
|
controller->destroy.notify = handle_tearing_controller_destroy;
|
||||||
|
wl_signal_add(&tearing_control->events.destroy, &controller->destroy);
|
||||||
|
wl_list_init(&controller->link);
|
||||||
|
|
||||||
|
wl_list_insert(&server->tearing_controllers, &controller->link);
|
||||||
|
}
|
|
@ -312,9 +312,9 @@ static void arrange_children(enum sway_container_layout layout, list_t *children
|
||||||
wlr_scene_node_set_position(&child->scene_tree->node, 0, title_bar_height);
|
wlr_scene_node_set_position(&child->scene_tree->node, 0, title_bar_height);
|
||||||
wlr_scene_node_reparent(&child->scene_tree->node, content);
|
wlr_scene_node_reparent(&child->scene_tree->node, content);
|
||||||
|
|
||||||
if (activated) {
|
int net_height = height - title_bar_height;
|
||||||
arrange_container(child, width, height - title_bar_height,
|
if (activated && width > 0 && net_height > 0) {
|
||||||
title_bar_height == 0, 0);
|
arrange_container(child, width, net_height, title_bar_height == 0, 0);
|
||||||
} else {
|
} else {
|
||||||
disable_container(child);
|
disable_container(child);
|
||||||
}
|
}
|
||||||
|
@ -341,9 +341,9 @@ static void arrange_children(enum sway_container_layout layout, list_t *children
|
||||||
wlr_scene_node_set_position(&child->scene_tree->node, 0, title_height);
|
wlr_scene_node_set_position(&child->scene_tree->node, 0, title_height);
|
||||||
wlr_scene_node_reparent(&child->scene_tree->node, content);
|
wlr_scene_node_reparent(&child->scene_tree->node, content);
|
||||||
|
|
||||||
if (activated) {
|
int net_height = height - title_bar_height;
|
||||||
arrange_container(child, width, height - title_height,
|
if (activated && width > 0 && net_height > 0) {
|
||||||
title_bar_height == 0, 0);
|
arrange_container(child, width, net_height, title_bar_height == 0, 0);
|
||||||
} else {
|
} else {
|
||||||
disable_container(child);
|
disable_container(child);
|
||||||
}
|
}
|
||||||
|
@ -359,8 +359,12 @@ static void arrange_children(enum sway_container_layout layout, list_t *children
|
||||||
wlr_scene_node_set_enabled(&child->border.tree->node, true);
|
wlr_scene_node_set_enabled(&child->border.tree->node, true);
|
||||||
wlr_scene_node_set_position(&child->scene_tree->node, 0, off);
|
wlr_scene_node_set_position(&child->scene_tree->node, 0, off);
|
||||||
wlr_scene_node_reparent(&child->scene_tree->node, content);
|
wlr_scene_node_reparent(&child->scene_tree->node, content);
|
||||||
arrange_container(child, width, cheight, true, gaps);
|
if (width > 0 && cheight > 0) {
|
||||||
off += cheight + gaps;
|
arrange_container(child, width, cheight, true, gaps);
|
||||||
|
off += cheight + gaps;
|
||||||
|
} else {
|
||||||
|
disable_container(child);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (layout == L_HORIZ) {
|
} else if (layout == L_HORIZ) {
|
||||||
int off = 0;
|
int off = 0;
|
||||||
|
@ -372,7 +376,12 @@ static void arrange_children(enum sway_container_layout layout, list_t *children
|
||||||
wlr_scene_node_set_position(&child->scene_tree->node, off, 0);
|
wlr_scene_node_set_position(&child->scene_tree->node, off, 0);
|
||||||
wlr_scene_node_reparent(&child->scene_tree->node, content);
|
wlr_scene_node_reparent(&child->scene_tree->node, content);
|
||||||
arrange_container(child, cwidth, height, true, gaps);
|
arrange_container(child, cwidth, height, true, gaps);
|
||||||
off += cwidth + gaps;
|
if (cwidth > 0 && height > 0) {
|
||||||
|
arrange_container(child, cwidth, height, true, gaps);
|
||||||
|
off += cwidth + gaps;
|
||||||
|
} else {
|
||||||
|
disable_container(child);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
sway_assert(false, "unreachable");
|
sway_assert(false, "unreachable");
|
||||||
|
@ -424,13 +433,14 @@ static void arrange_container(struct sway_container *con,
|
||||||
int border_bottom = con->current.border_bottom ? border_width : 0;
|
int border_bottom = con->current.border_bottom ? border_width : 0;
|
||||||
int border_left = con->current.border_left ? border_width : 0;
|
int border_left = con->current.border_left ? border_width : 0;
|
||||||
int border_right = con->current.border_right ? border_width : 0;
|
int border_right = con->current.border_right ? border_width : 0;
|
||||||
|
int vert_border_height = MAX(0, height - border_top - border_bottom);
|
||||||
|
|
||||||
wlr_scene_rect_set_size(con->border.top, width, border_top);
|
wlr_scene_rect_set_size(con->border.top, width, border_top);
|
||||||
wlr_scene_rect_set_size(con->border.bottom, width, border_bottom);
|
wlr_scene_rect_set_size(con->border.bottom, width, border_bottom);
|
||||||
wlr_scene_rect_set_size(con->border.left,
|
wlr_scene_rect_set_size(con->border.left,
|
||||||
border_left, height - border_top - border_bottom);
|
border_left, vert_border_height);
|
||||||
wlr_scene_rect_set_size(con->border.right,
|
wlr_scene_rect_set_size(con->border.right,
|
||||||
border_right, height - border_top - border_bottom);
|
border_right, vert_border_height);
|
||||||
|
|
||||||
wlr_scene_node_set_position(&con->border.top->node, 0, 0);
|
wlr_scene_node_set_position(&con->border.top->node, 0, 0);
|
||||||
wlr_scene_node_set_position(&con->border.bottom->node,
|
wlr_scene_node_set_position(&con->border.bottom->node,
|
||||||
|
@ -559,7 +569,7 @@ static void arrange_output(struct sway_output *output, int width, int height) {
|
||||||
for (int i = 0; i < output->current.workspaces->length; i++) {
|
for (int i = 0; i < output->current.workspaces->length; i++) {
|
||||||
struct sway_workspace *child = output->current.workspaces->items[i];
|
struct sway_workspace *child = output->current.workspaces->items[i];
|
||||||
|
|
||||||
bool activated = output->current.active_workspace == child;
|
bool activated = output->current.active_workspace == child && output->wlr_output->enabled;
|
||||||
|
|
||||||
wlr_scene_node_reparent(&child->layers.tiling->node, output->layers.tiling);
|
wlr_scene_node_reparent(&child->layers.tiling->node, output->layers.tiling);
|
||||||
wlr_scene_node_reparent(&child->layers.fullscreen->node, output->layers.fullscreen);
|
wlr_scene_node_reparent(&child->layers.fullscreen->node, output->layers.fullscreen);
|
||||||
|
@ -612,9 +622,11 @@ void arrange_popups(struct wlr_scene_tree *popups) {
|
||||||
struct sway_popup_desc *popup = scene_descriptor_try_get(node,
|
struct sway_popup_desc *popup = scene_descriptor_try_get(node,
|
||||||
SWAY_SCENE_DESC_POPUP);
|
SWAY_SCENE_DESC_POPUP);
|
||||||
|
|
||||||
int lx, ly;
|
if (popup) {
|
||||||
wlr_scene_node_coords(popup->relative, &lx, &ly);
|
int lx, ly;
|
||||||
wlr_scene_node_set_position(node, lx, ly);
|
wlr_scene_node_coords(popup->relative, &lx, &ly);
|
||||||
|
wlr_scene_node_set_position(node, lx, ly);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -632,6 +644,15 @@ static void arrange_root(struct sway_root *root) {
|
||||||
for (int i = 0; i < root->scratchpad->length; i++) {
|
for (int i = 0; i < root->scratchpad->length; i++) {
|
||||||
struct sway_container *con = root->scratchpad->items[i];
|
struct sway_container *con = root->scratchpad->items[i];
|
||||||
|
|
||||||
|
// When a container is moved to a scratchpad, it's possible that it
|
||||||
|
// was moved into a floating container as part of the same transaction.
|
||||||
|
// In this case, we need to make sure we reparent all the container's
|
||||||
|
// children so that disabling the container will disable all descendants.
|
||||||
|
if (!con->view) for (int ii = 0; ii < con->current.children->length; ii++) {
|
||||||
|
struct sway_container *child = con->current.children->items[ii];
|
||||||
|
wlr_scene_node_reparent(&child->scene_tree->node, con->content_tree);
|
||||||
|
}
|
||||||
|
|
||||||
wlr_scene_node_set_enabled(&con->scene_tree->node, false);
|
wlr_scene_node_set_enabled(&con->scene_tree->node, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -640,6 +661,8 @@ static void arrange_root(struct sway_root *root) {
|
||||||
struct sway_output *output = root->outputs->items[i];
|
struct sway_output *output = root->outputs->items[i];
|
||||||
struct sway_workspace *ws = output->current.active_workspace;
|
struct sway_workspace *ws = output->current.active_workspace;
|
||||||
|
|
||||||
|
wlr_scene_output_set_position(output->scene_output, output->lx, output->ly);
|
||||||
|
|
||||||
if (ws) {
|
if (ws) {
|
||||||
arrange_workspace_floating(ws);
|
arrange_workspace_floating(ws);
|
||||||
}
|
}
|
||||||
|
|
|
@ -299,18 +299,17 @@ static void handle_commit(struct wl_listener *listener, void *data) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct wlr_box new_geo;
|
struct wlr_box *new_geo = &xdg_surface->geometry;
|
||||||
wlr_xdg_surface_get_geometry(xdg_surface, &new_geo);
|
bool new_size = new_geo->width != view->geometry.width ||
|
||||||
bool new_size = new_geo.width != view->geometry.width ||
|
new_geo->height != view->geometry.height ||
|
||||||
new_geo.height != view->geometry.height ||
|
new_geo->x != view->geometry.x ||
|
||||||
new_geo.x != view->geometry.x ||
|
new_geo->y != view->geometry.y;
|
||||||
new_geo.y != view->geometry.y;
|
|
||||||
|
|
||||||
if (new_size) {
|
if (new_size) {
|
||||||
// The client changed its surface size in this commit. For floating
|
// The client changed its surface size in this commit. For floating
|
||||||
// containers, we resize the container to match. For tiling containers,
|
// containers, we resize the container to match. For tiling containers,
|
||||||
// we only recenter the surface.
|
// we only recenter the surface.
|
||||||
memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box));
|
memcpy(&view->geometry, new_geo, sizeof(struct wlr_box));
|
||||||
if (container_is_floating(view->container)) {
|
if (container_is_floating(view->container)) {
|
||||||
view_update_size(view);
|
view_update_size(view);
|
||||||
// Only set the toplevel size the current container actually has a size.
|
// Only set the toplevel size the current container actually has a size.
|
||||||
|
@ -463,12 +462,8 @@ static void handle_map(struct wl_listener *listener, void *data) {
|
||||||
struct sway_view *view = &xdg_shell_view->view;
|
struct sway_view *view = &xdg_shell_view->view;
|
||||||
struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_toplevel;
|
struct wlr_xdg_toplevel *toplevel = view->wlr_xdg_toplevel;
|
||||||
|
|
||||||
view->natural_width = toplevel->base->current.geometry.width;
|
view->natural_width = toplevel->base->geometry.width;
|
||||||
view->natural_height = toplevel->base->current.geometry.height;
|
view->natural_height = toplevel->base->geometry.height;
|
||||||
if (!view->natural_width && !view->natural_height) {
|
|
||||||
view->natural_width = toplevel->base->surface->current.width;
|
|
||||||
view->natural_height = toplevel->base->surface->current.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool csd = false;
|
bool csd = false;
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,7 @@ static void unmanaged_handle_map(struct wl_listener *listener, void *data) {
|
||||||
surface->set_geometry.notify = unmanaged_handle_set_geometry;
|
surface->set_geometry.notify = unmanaged_handle_set_geometry;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wlr_xwayland_or_surface_wants_focus(xsurface)) {
|
if (wlr_xwayland_surface_override_redirect_wants_focus(xsurface)) {
|
||||||
struct sway_seat *seat = input_manager_current_seat();
|
struct sway_seat *seat = input_manager_current_seat();
|
||||||
struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland;
|
struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland;
|
||||||
wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
|
wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
|
||||||
|
@ -96,7 +96,7 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) {
|
||||||
// This simply returns focus to the parent surface if there's one available.
|
// This simply returns focus to the parent surface if there's one available.
|
||||||
// This seems to handle JetBrains issues.
|
// This seems to handle JetBrains issues.
|
||||||
if (xsurface->parent && xsurface->parent->surface
|
if (xsurface->parent && xsurface->parent->surface
|
||||||
&& wlr_xwayland_or_surface_wants_focus(xsurface->parent)) {
|
&& wlr_xwayland_surface_override_redirect_wants_focus(xsurface->parent)) {
|
||||||
seat_set_focus_surface(seat, xsurface->parent->surface, false);
|
seat_set_focus_surface(seat, xsurface->parent->surface, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -289,7 +289,6 @@ static void set_activated(struct sway_view *view, bool activated) {
|
||||||
}
|
}
|
||||||
|
|
||||||
wlr_xwayland_surface_activate(surface, activated);
|
wlr_xwayland_surface_activate(surface, activated);
|
||||||
wlr_xwayland_surface_restack(surface, NULL, XCB_STACK_MODE_ABOVE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_tiled(struct sway_view *view, bool tiled) {
|
static void set_tiled(struct sway_view *view, bool tiled) {
|
||||||
|
@ -297,7 +296,7 @@ static void set_tiled(struct sway_view *view, bool tiled) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
|
struct wlr_xwayland_surface *surface = view->wlr_xwayland_surface;
|
||||||
wlr_xwayland_surface_set_maximized(surface, tiled);
|
wlr_xwayland_surface_set_maximized(surface, tiled, tiled);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_fullscreen(struct sway_view *view, bool fullscreen) {
|
static void set_fullscreen(struct sway_view *view, bool fullscreen) {
|
||||||
|
|
|
@ -578,7 +578,7 @@ static void handle_tablet_tool_position(struct sway_cursor *cursor,
|
||||||
// tablet events until the drag is released, even if we are now over a
|
// tablet events until the drag is released, even if we are now over a
|
||||||
// non-tablet surface.
|
// non-tablet surface.
|
||||||
if (!cursor->simulating_pointer_from_tool_tip &&
|
if (!cursor->simulating_pointer_from_tool_tip &&
|
||||||
((surface && wlr_surface_accepts_tablet_v2(tablet->tablet_v2, surface)) ||
|
((surface && wlr_surface_accepts_tablet_v2(surface, tablet->tablet_v2)) ||
|
||||||
wlr_tablet_tool_v2_has_implicit_grab(tool->tablet_v2_tool))) {
|
wlr_tablet_tool_v2_has_implicit_grab(tool->tablet_v2_tool))) {
|
||||||
seatop_tablet_tool_motion(seat, tool, time_msec);
|
seatop_tablet_tool_motion(seat, tool, time_msec);
|
||||||
} else {
|
} else {
|
||||||
|
@ -664,7 +664,7 @@ static void handle_tool_tip(struct wl_listener *listener, void *data) {
|
||||||
dispatch_cursor_button(cursor, &event->tablet->base, event->time_msec,
|
dispatch_cursor_button(cursor, &event->tablet->base, event->time_msec,
|
||||||
BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED);
|
BTN_LEFT, WL_POINTER_BUTTON_STATE_RELEASED);
|
||||||
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
|
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
|
||||||
} else if (!surface || !wlr_surface_accepts_tablet_v2(tablet_v2, surface)) {
|
} else if (!surface || !wlr_surface_accepts_tablet_v2(surface, tablet_v2)) {
|
||||||
// If we started holding the tool tip down on a surface that accepts
|
// If we started holding the tool tip down on a surface that accepts
|
||||||
// tablet v2, we should notify that surface if it gets released over a
|
// tablet v2, we should notify that surface if it gets released over a
|
||||||
// surface that doesn't support v2.
|
// surface that doesn't support v2.
|
||||||
|
@ -749,7 +749,7 @@ static void handle_tool_button(struct wl_listener *listener, void *data) {
|
||||||
bool mod_pressed = modifiers & config->floating_mod;
|
bool mod_pressed = modifiers & config->floating_mod;
|
||||||
|
|
||||||
bool surface_supports_tablet_events =
|
bool surface_supports_tablet_events =
|
||||||
surface && wlr_surface_accepts_tablet_v2(tablet_v2, surface);
|
surface && wlr_surface_accepts_tablet_v2(surface, tablet_v2);
|
||||||
|
|
||||||
// Simulate pointer when:
|
// Simulate pointer when:
|
||||||
// 1. The modifier key is pressed, OR
|
// 1. The modifier key is pressed, OR
|
||||||
|
@ -1047,6 +1047,7 @@ void sway_cursor_destroy(struct sway_cursor *cursor) {
|
||||||
wl_list_remove(&cursor->touch_frame.link);
|
wl_list_remove(&cursor->touch_frame.link);
|
||||||
wl_list_remove(&cursor->tool_axis.link);
|
wl_list_remove(&cursor->tool_axis.link);
|
||||||
wl_list_remove(&cursor->tool_tip.link);
|
wl_list_remove(&cursor->tool_tip.link);
|
||||||
|
wl_list_remove(&cursor->tool_proximity.link);
|
||||||
wl_list_remove(&cursor->tool_button.link);
|
wl_list_remove(&cursor->tool_button.link);
|
||||||
wl_list_remove(&cursor->request_set_cursor.link);
|
wl_list_remove(&cursor->request_set_cursor.link);
|
||||||
|
|
||||||
|
@ -1212,7 +1213,7 @@ uint32_t get_mouse_bindsym(const char *name, char **error) {
|
||||||
SWAY_SCROLL_UP, SWAY_SCROLL_DOWN, SWAY_SCROLL_LEFT,
|
SWAY_SCROLL_UP, SWAY_SCROLL_DOWN, SWAY_SCROLL_LEFT,
|
||||||
SWAY_SCROLL_RIGHT, BTN_SIDE, BTN_EXTRA};
|
SWAY_SCROLL_RIGHT, BTN_SIDE, BTN_EXTRA};
|
||||||
return buttons[number - 1];
|
return buttons[number - 1];
|
||||||
} else if (strncmp(name, "BTN_", strlen("BTN_")) == 0) {
|
} else if (has_prefix(name, "BTN_")) {
|
||||||
// Get event code from name
|
// Get event code from name
|
||||||
int code = libevdev_event_code_from_name(EV_KEY, name);
|
int code = libevdev_event_code_from_name(EV_KEY, name);
|
||||||
if (code == -1) {
|
if (code == -1) {
|
||||||
|
@ -1237,7 +1238,7 @@ uint32_t get_mouse_bindcode(const char *name, char **error) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
const char *event = libevdev_event_code_get_name(EV_KEY, code);
|
const char *event = libevdev_event_code_get_name(EV_KEY, code);
|
||||||
if (!event || strncmp(event, "BTN_", strlen("BTN_")) != 0) {
|
if (!event || !has_prefix(event, "BTN_")) {
|
||||||
*error = format_str("Event code %d (%s) is not a button",
|
*error = format_str("Event code %d (%s) is not a button",
|
||||||
code, event ? event : "(null)");
|
code, event ? event : "(null)");
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <wlr/config.h>
|
#include <wlr/config.h>
|
||||||
#include <wlr/backend/libinput.h>
|
|
||||||
#include <wlr/types/wlr_cursor.h>
|
#include <wlr/types/wlr_cursor.h>
|
||||||
#include <wlr/types/wlr_keyboard_group.h>
|
#include <wlr/types/wlr_keyboard_group.h>
|
||||||
#include <wlr/types/wlr_virtual_keyboard_v1.h>
|
#include <wlr/types/wlr_virtual_keyboard_v1.h>
|
||||||
|
@ -578,7 +577,7 @@ void input_manager_configure_all_input_mappings(void) {
|
||||||
void input_manager_apply_input_config(struct input_config *input_config) {
|
void input_manager_apply_input_config(struct input_config *input_config) {
|
||||||
struct sway_input_device *input_device = NULL;
|
struct sway_input_device *input_device = NULL;
|
||||||
bool wildcard = strcmp(input_config->identifier, "*") == 0;
|
bool wildcard = strcmp(input_config->identifier, "*") == 0;
|
||||||
bool type_wildcard = strncmp(input_config->identifier, "type:", 5) == 0;
|
bool type_wildcard = has_prefix(input_config->identifier, "type:");
|
||||||
wl_list_for_each(input_device, &server.input->devices, link) {
|
wl_list_for_each(input_device, &server.input->devices, link) {
|
||||||
bool type_matches = type_wildcard &&
|
bool type_matches = type_wildcard &&
|
||||||
strcmp(input_device_get_type(input_device), input_config->identifier + 5) == 0;
|
strcmp(input_device_get_type(input_device), input_config->identifier + 5) == 0;
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
#include <wlr/config.h>
|
#include <wlr/config.h>
|
||||||
#include <wlr/backend/multi.h>
|
#include <wlr/backend/multi.h>
|
||||||
#include <wlr/interfaces/wlr_keyboard.h>
|
#include <wlr/interfaces/wlr_keyboard.h>
|
||||||
|
#include <wlr/types/wlr_cursor.h>
|
||||||
#include <wlr/types/wlr_keyboard.h>
|
#include <wlr/types/wlr_keyboard.h>
|
||||||
#include <wlr/types/wlr_keyboard_group.h>
|
#include <wlr/types/wlr_keyboard_group.h>
|
||||||
#include <xkbcommon/xkbcommon-names.h>
|
#include <xkbcommon/xkbcommon-names.h>
|
||||||
|
@ -267,6 +268,7 @@ static bool keyboard_execute_compositor_binding(struct sway_keyboard *keyboard,
|
||||||
const xkb_keysym_t *pressed_keysyms, uint32_t modifiers, size_t keysyms_len) {
|
const xkb_keysym_t *pressed_keysyms, uint32_t modifiers, size_t keysyms_len) {
|
||||||
for (size_t i = 0; i < keysyms_len; ++i) {
|
for (size_t i = 0; i < keysyms_len; ++i) {
|
||||||
xkb_keysym_t keysym = pressed_keysyms[i];
|
xkb_keysym_t keysym = pressed_keysyms[i];
|
||||||
|
|
||||||
if (keysym >= XKB_KEY_XF86Switch_VT_1 &&
|
if (keysym >= XKB_KEY_XF86Switch_VT_1 &&
|
||||||
keysym <= XKB_KEY_XF86Switch_VT_12) {
|
keysym <= XKB_KEY_XF86Switch_VT_12) {
|
||||||
#if WLR_HAS_SESSION
|
#if WLR_HAS_SESSION
|
||||||
|
@ -282,6 +284,36 @@ static bool keyboard_execute_compositor_binding(struct sway_keyboard *keyboard,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool keyboard_execute_pointer_keysyms(struct sway_keyboard *keyboard,
|
||||||
|
uint32_t time, const xkb_keysym_t *pressed_keysyms, size_t keysyms_len,
|
||||||
|
enum wl_keyboard_key_state state) {
|
||||||
|
struct sway_cursor *cursor = keyboard->seat_device->sway_seat->cursor;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < keysyms_len; ++i) {
|
||||||
|
xkb_keysym_t keysym = pressed_keysyms[i];
|
||||||
|
|
||||||
|
uint32_t button = wlr_keyboard_keysym_to_pointer_button(keysym);
|
||||||
|
if (button != 0) {
|
||||||
|
dispatch_cursor_button(cursor, &keyboard->wlr->base, time, button,
|
||||||
|
(enum wl_pointer_button_state)state);
|
||||||
|
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dx, dy;
|
||||||
|
wlr_keyboard_keysym_to_pointer_motion(keysym, &dx, &dy);
|
||||||
|
if (state == WL_KEYBOARD_KEY_STATE_PRESSED && (dx != 0 || dy != 0)) {
|
||||||
|
dx *= 10;
|
||||||
|
dy *= 10;
|
||||||
|
pointer_motion(cursor, time, &keyboard->wlr->base, dx, dy, dx, dy);
|
||||||
|
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get keysyms and modifiers from the keyboard as xkb sees them.
|
* Get keysyms and modifiers from the keyboard as xkb sees them.
|
||||||
*
|
*
|
||||||
|
@ -507,6 +539,11 @@ static void handle_key_event(struct sway_keyboard *keyboard,
|
||||||
keyboard, keyinfo.raw_keysyms, keyinfo.raw_modifiers,
|
keyboard, keyinfo.raw_keysyms, keyinfo.raw_modifiers,
|
||||||
keyinfo.raw_keysyms_len);
|
keyinfo.raw_keysyms_len);
|
||||||
}
|
}
|
||||||
|
if (!handled) {
|
||||||
|
handled = keyboard_execute_pointer_keysyms(keyboard, event->time_msec,
|
||||||
|
keyinfo.translated_keysyms, keyinfo.translated_keysyms_len,
|
||||||
|
event->state);
|
||||||
|
}
|
||||||
|
|
||||||
if (event->state == WL_KEYBOARD_KEY_STATE_RELEASED) {
|
if (event->state == WL_KEYBOARD_KEY_STATE_RELEASED) {
|
||||||
// If the pressed event was sent to a client and we have a focused
|
// If the pressed event was sent to a client and we have a focused
|
||||||
|
@ -1028,13 +1065,6 @@ static void sway_keyboard_set_layout(struct sway_keyboard *keyboard,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the seat has no active keyboard, set this one
|
|
||||||
struct wlr_seat *seat = keyboard->seat_device->sway_seat->wlr_seat;
|
|
||||||
struct wlr_keyboard *current_keyboard = seat->keyboard_state.keyboard;
|
|
||||||
if (current_keyboard == NULL) {
|
|
||||||
wlr_seat_set_keyboard(seat, keyboard->wlr);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keymap_changed) {
|
if (keymap_changed) {
|
||||||
ipc_event_input("xkb_keymap",
|
ipc_event_input("xkb_keymap",
|
||||||
keyboard->seat_device->input_device);
|
keyboard->seat_device->input_device);
|
||||||
|
@ -1078,6 +1108,13 @@ void sway_keyboard_configure(struct sway_keyboard *keyboard) {
|
||||||
sway_keyboard_set_layout(keyboard, input_config);
|
sway_keyboard_set_layout(keyboard, input_config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If the seat has no active keyboard, set this one
|
||||||
|
struct wlr_seat *seat = keyboard->seat_device->sway_seat->wlr_seat;
|
||||||
|
struct wlr_keyboard *current_keyboard = seat->keyboard_state.keyboard;
|
||||||
|
if (current_keyboard == NULL) {
|
||||||
|
wlr_seat_set_keyboard(seat, keyboard->wlr);
|
||||||
|
}
|
||||||
|
|
||||||
wl_list_remove(&keyboard->keyboard_key.link);
|
wl_list_remove(&keyboard->keyboard_key.link);
|
||||||
wl_signal_add(&keyboard->wlr->events.key, &keyboard->keyboard_key);
|
wl_signal_add(&keyboard->wlr->events.key, &keyboard->keyboard_key);
|
||||||
keyboard->keyboard_key.notify = handle_keyboard_key;
|
keyboard->keyboard_key.notify = handle_keyboard_key;
|
||||||
|
|
|
@ -272,6 +272,10 @@ bool sway_input_configure_libinput_device(struct sway_input_device *input_device
|
||||||
}
|
}
|
||||||
if (ic->drag_lock != INT_MIN) {
|
if (ic->drag_lock != INT_MIN) {
|
||||||
changed |= set_tap_drag_lock(device, ic->drag_lock);
|
changed |= set_tap_drag_lock(device, ic->drag_lock);
|
||||||
|
} else {
|
||||||
|
#if HAVE_LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY
|
||||||
|
changed |= set_tap_drag_lock(device, LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (ic->pointer_accel != FLT_MIN) {
|
if (ic->pointer_accel != FLT_MIN) {
|
||||||
changed |= set_accel_speed(device, ic->pointer_accel);
|
changed |= set_accel_speed(device, ic->pointer_accel);
|
||||||
|
@ -354,8 +358,12 @@ void sway_input_reset_libinput_device(struct sway_input_device *input_device) {
|
||||||
libinput_device_config_tap_get_default_button_map(device));
|
libinput_device_config_tap_get_default_button_map(device));
|
||||||
changed |= set_tap_drag(device,
|
changed |= set_tap_drag(device,
|
||||||
libinput_device_config_tap_get_default_drag_enabled(device));
|
libinput_device_config_tap_get_default_drag_enabled(device));
|
||||||
|
#if HAVE_LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY
|
||||||
|
changed |= set_tap_drag_lock(device, LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY);
|
||||||
|
#else
|
||||||
changed |= set_tap_drag_lock(device,
|
changed |= set_tap_drag_lock(device,
|
||||||
libinput_device_config_tap_get_default_drag_lock_enabled(device));
|
libinput_device_config_tap_get_default_drag_lock_enabled(device));
|
||||||
|
#endif
|
||||||
changed |= set_accel_speed(device,
|
changed |= set_accel_speed(device,
|
||||||
libinput_device_config_accel_get_default_speed(device));
|
libinput_device_config_accel_get_default_speed(device));
|
||||||
changed |= set_rotation_angle(device,
|
changed |= set_rotation_angle(device,
|
||||||
|
@ -409,13 +417,9 @@ bool sway_libinput_device_is_builtin(struct sway_input_device *sway_device) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const char prefix_platform[] = "platform-";
|
if (has_prefix(id_path, "platform-")) {
|
||||||
if (strncmp(id_path, prefix_platform, strlen(prefix_platform)) != 0) {
|
return true;
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const char prefix_pci[] = "pci-";
|
return has_prefix(id_path, "pci-") && strstr(id_path, "-platform-");
|
||||||
const char infix_platform[] = "-platform-";
|
|
||||||
return (strncmp(id_path, prefix_pci, strlen(prefix_pci)) == 0) &&
|
|
||||||
strstr(id_path, infix_platform);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -647,10 +647,6 @@ static void seat_reset_input_config(struct sway_seat *seat,
|
||||||
sway_device->input_device->wlr_device, NULL);
|
sway_device->input_device->wlr_device, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool has_prefix(const char *str, const char *prefix) {
|
|
||||||
return strncmp(str, prefix, strlen(prefix)) == 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the name of the built-in output, if any. Returns NULL if there isn't
|
* Get the name of the built-in output, if any. Returns NULL if there isn't
|
||||||
* exactly one built-in output.
|
* exactly one built-in output.
|
||||||
|
@ -1094,6 +1090,7 @@ static void seat_send_unfocus(struct sway_node *node, struct sway_seat *seat) {
|
||||||
static int handle_urgent_timeout(void *data) {
|
static int handle_urgent_timeout(void *data) {
|
||||||
struct sway_view *view = data;
|
struct sway_view *view = data;
|
||||||
view_set_urgent(view, false);
|
view_set_urgent(view, false);
|
||||||
|
container_update_itself_and_parents(view->container);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -273,7 +273,7 @@ static void handle_tablet_tool_tip(struct sway_seat *seat,
|
||||||
// Handle tapping on an xwayland unmanaged view
|
// Handle tapping on an xwayland unmanaged view
|
||||||
else if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(surface)) &&
|
else if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(surface)) &&
|
||||||
xsurface->override_redirect &&
|
xsurface->override_redirect &&
|
||||||
wlr_xwayland_or_surface_wants_focus(xsurface)) {
|
wlr_xwayland_surface_override_redirect_wants_focus(xsurface)) {
|
||||||
struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland;
|
struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland;
|
||||||
wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
|
wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
|
||||||
seat_set_focus_surface(seat, xsurface->surface, false);
|
seat_set_focus_surface(seat, xsurface->surface, false);
|
||||||
|
@ -355,6 +355,13 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
|
||||||
struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
|
struct wlr_keyboard *keyboard = wlr_seat_get_keyboard(seat->wlr_seat);
|
||||||
uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
|
uint32_t modifiers = keyboard ? wlr_keyboard_get_modifiers(keyboard) : 0;
|
||||||
|
|
||||||
|
bool mod_pressed = modifiers & config->floating_mod;
|
||||||
|
uint32_t mod_move_btn = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT;
|
||||||
|
uint32_t mod_resize_btn = config->floating_mod_inverse ? BTN_LEFT : BTN_RIGHT;
|
||||||
|
bool mod_move_btn_pressed = mod_pressed && button == mod_move_btn;
|
||||||
|
bool mod_resize_btn_pressed = mod_pressed && button == mod_resize_btn;
|
||||||
|
bool titlebar_left_btn_pressed = on_titlebar && button == BTN_LEFT;
|
||||||
|
|
||||||
// Handle mouse bindings
|
// Handle mouse bindings
|
||||||
if (trigger_pointer_button_binding(seat, device, button, state, modifiers,
|
if (trigger_pointer_button_binding(seat, device, button, state, modifiers,
|
||||||
on_titlebar, on_border, on_contents, on_workspace)) {
|
on_titlebar, on_border, on_contents, on_workspace)) {
|
||||||
|
@ -403,33 +410,28 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle tiling resize via mod
|
// Handle tiling resize via mod
|
||||||
bool mod_pressed = modifiers & config->floating_mod;
|
if (cont && !is_floating_or_child && mod_pressed && mod_resize_btn_pressed &&
|
||||||
if (cont && !is_floating_or_child && mod_pressed &&
|
|
||||||
state == WL_POINTER_BUTTON_STATE_PRESSED) {
|
state == WL_POINTER_BUTTON_STATE_PRESSED) {
|
||||||
uint32_t btn_resize = config->floating_mod_inverse ?
|
edge = 0;
|
||||||
BTN_LEFT : BTN_RIGHT;
|
edge |= cursor->cursor->x > cont->pending.x + cont->pending.width / 2 ?
|
||||||
if (button == btn_resize) {
|
WLR_EDGE_RIGHT : WLR_EDGE_LEFT;
|
||||||
edge = 0;
|
edge |= cursor->cursor->y > cont->pending.y + cont->pending.height / 2 ?
|
||||||
edge |= cursor->cursor->x > cont->pending.x + cont->pending.width / 2 ?
|
WLR_EDGE_BOTTOM : WLR_EDGE_TOP;
|
||||||
WLR_EDGE_RIGHT : WLR_EDGE_LEFT;
|
|
||||||
edge |= cursor->cursor->y > cont->pending.y + cont->pending.height / 2 ?
|
|
||||||
WLR_EDGE_BOTTOM : WLR_EDGE_TOP;
|
|
||||||
|
|
||||||
const char *image = NULL;
|
const char *image = NULL;
|
||||||
if (edge == (WLR_EDGE_LEFT | WLR_EDGE_TOP)) {
|
if (edge == (WLR_EDGE_LEFT | WLR_EDGE_TOP)) {
|
||||||
image = "nw-resize";
|
image = "nw-resize";
|
||||||
} else if (edge == (WLR_EDGE_TOP | WLR_EDGE_RIGHT)) {
|
} else if (edge == (WLR_EDGE_TOP | WLR_EDGE_RIGHT)) {
|
||||||
image = "ne-resize";
|
image = "ne-resize";
|
||||||
} else if (edge == (WLR_EDGE_RIGHT | WLR_EDGE_BOTTOM)) {
|
} else if (edge == (WLR_EDGE_RIGHT | WLR_EDGE_BOTTOM)) {
|
||||||
image = "se-resize";
|
image = "se-resize";
|
||||||
} else if (edge == (WLR_EDGE_BOTTOM | WLR_EDGE_LEFT)) {
|
} else if (edge == (WLR_EDGE_BOTTOM | WLR_EDGE_LEFT)) {
|
||||||
image = "sw-resize";
|
image = "sw-resize";
|
||||||
}
|
|
||||||
cursor_set_image(seat->cursor, image, NULL);
|
|
||||||
seat_set_focus_container(seat, cont);
|
|
||||||
seatop_begin_resize_tiling(seat, cont, edge);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
cursor_set_image(seat->cursor, image, NULL);
|
||||||
|
seat_set_focus_container(seat, cont);
|
||||||
|
seatop_begin_resize_tiling(seat, cont, edge);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle changing focus when clicking on a container
|
// Handle changing focus when clicking on a container
|
||||||
|
@ -454,12 +456,10 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
|
||||||
|
|
||||||
// Handle beginning floating move
|
// Handle beginning floating move
|
||||||
if (cont && is_floating_or_child && !is_fullscreen_or_child &&
|
if (cont && is_floating_or_child && !is_fullscreen_or_child &&
|
||||||
state == WL_POINTER_BUTTON_STATE_PRESSED) {
|
state == WL_POINTER_BUTTON_STATE_PRESSED &&
|
||||||
uint32_t btn_move = config->floating_mod_inverse ? BTN_RIGHT : BTN_LEFT;
|
(mod_move_btn_pressed || titlebar_left_btn_pressed)) {
|
||||||
if (button == btn_move && (mod_pressed || on_titlebar)) {
|
seatop_begin_move_floating(seat, container_toplevel_ancestor(cont));
|
||||||
seatop_begin_move_floating(seat, container_toplevel_ancestor(cont));
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle beginning floating resize
|
// Handle beginning floating resize
|
||||||
|
@ -473,9 +473,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Via mod+click
|
// Via mod+click
|
||||||
uint32_t btn_resize = config->floating_mod_inverse ?
|
if (mod_resize_btn_pressed) {
|
||||||
BTN_LEFT : BTN_RIGHT;
|
|
||||||
if (mod_pressed && button == btn_resize) {
|
|
||||||
struct sway_container *floater = container_toplevel_ancestor(cont);
|
struct sway_container *floater = container_toplevel_ancestor(cont);
|
||||||
edge = 0;
|
edge = 0;
|
||||||
edge |= cursor->cursor->x > floater->pending.x + floater->pending.width / 2 ?
|
edge |= cursor->cursor->x > floater->pending.x + floater->pending.width / 2 ?
|
||||||
|
@ -489,7 +487,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle moving a tiling container
|
// Handle moving a tiling container
|
||||||
if (config->tiling_drag && (mod_pressed || on_titlebar) &&
|
if (config->tiling_drag && (mod_move_btn_pressed || titlebar_left_btn_pressed) &&
|
||||||
state == WL_POINTER_BUTTON_STATE_PRESSED && !is_floating_or_child &&
|
state == WL_POINTER_BUTTON_STATE_PRESSED && !is_floating_or_child &&
|
||||||
cont && cont->pending.fullscreen_mode == FULLSCREEN_NONE) {
|
cont && cont->pending.fullscreen_mode == FULLSCREEN_NONE) {
|
||||||
// If moving a container by its title bar, use a threshold for the drag
|
// If moving a container by its title bar, use a threshold for the drag
|
||||||
|
@ -498,7 +496,6 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
|
||||||
} else {
|
} else {
|
||||||
seatop_begin_move_tiling(seat, cont);
|
seatop_begin_move_tiling(seat, cont);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -521,7 +518,7 @@ static void handle_button(struct sway_seat *seat, uint32_t time_msec,
|
||||||
if (surface &&
|
if (surface &&
|
||||||
(xsurface = wlr_xwayland_surface_try_from_wlr_surface(surface)) &&
|
(xsurface = wlr_xwayland_surface_try_from_wlr_surface(surface)) &&
|
||||||
xsurface->override_redirect &&
|
xsurface->override_redirect &&
|
||||||
wlr_xwayland_or_surface_wants_focus(xsurface)) {
|
wlr_xwayland_surface_override_redirect_wants_focus(xsurface)) {
|
||||||
struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland;
|
struct wlr_xwayland *xwayland = server.xwayland.wlr_xwayland;
|
||||||
wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
|
wlr_xwayland_set_seat(xwayland, seat->wlr_seat);
|
||||||
seat_set_focus_surface(seat, xsurface->surface, false);
|
seat_set_focus_surface(seat, xsurface->surface, false);
|
||||||
|
@ -667,7 +664,7 @@ static void handle_touch_down(struct sway_seat *seat,
|
||||||
double sx, sy;
|
double sx, sy;
|
||||||
node_at_coords(seat, seat->touch_x, seat->touch_y, &surface, &sx, &sy);
|
node_at_coords(seat, seat->touch_x, seat->touch_y, &surface, &sx, &sy);
|
||||||
|
|
||||||
if (surface && wlr_surface_accepts_touch(wlr_seat, surface)) {
|
if (surface && wlr_surface_accepts_touch(surface, wlr_seat)) {
|
||||||
if (seat_is_input_allowed(seat, surface)) {
|
if (seat_is_input_allowed(seat, surface)) {
|
||||||
cursor->simulating_pointer_from_touch = false;
|
cursor->simulating_pointer_from_touch = false;
|
||||||
seatop_begin_touch_down(seat, surface, event, sx, sy, lx, ly);
|
seatop_begin_touch_down(seat, surface, event, sx, sy, lx, ly);
|
||||||
|
|
|
@ -363,7 +363,7 @@ void sway_tablet_pad_set_focus(struct sway_tablet_pad *tablet_pad,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (surface == NULL ||
|
if (surface == NULL ||
|
||||||
!wlr_surface_accepts_tablet_v2(tablet_pad->tablet->tablet_v2, surface)) {
|
!wlr_surface_accepts_tablet_v2(surface, tablet_pad->tablet->tablet_v2)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,8 +10,7 @@
|
||||||
#include "sway/input/text_input_popup.h"
|
#include "sway/input/text_input_popup.h"
|
||||||
#include "sway/layers.h"
|
#include "sway/layers.h"
|
||||||
#include "sway/server.h"
|
#include "sway/server.h"
|
||||||
|
#include <wlr/types/wlr_session_lock_v1.h>
|
||||||
static void input_popup_update(struct sway_input_popup *popup);
|
|
||||||
|
|
||||||
static struct sway_text_input *relay_get_focusable_text_input(
|
static struct sway_text_input *relay_get_focusable_text_input(
|
||||||
struct sway_input_method_relay *relay) {
|
struct sway_input_method_relay *relay) {
|
||||||
|
@ -128,6 +127,89 @@ static void handle_im_destroy(struct wl_listener *listener, void *data) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void constrain_popup(struct sway_input_popup *popup) {
|
||||||
|
struct sway_text_input *text_input =
|
||||||
|
relay_get_focused_text_input(popup->relay);
|
||||||
|
|
||||||
|
if (!popup->desc.relative) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_box parent = {0};
|
||||||
|
wlr_scene_node_coords(&popup->desc.relative->parent->node, &parent.x, &parent.y);
|
||||||
|
|
||||||
|
struct wlr_box geo = {0};
|
||||||
|
struct wlr_output *output;
|
||||||
|
|
||||||
|
if (popup->desc.view) {
|
||||||
|
struct sway_view *view = popup->desc.view;
|
||||||
|
output = wlr_output_layout_output_at(root->output_layout,
|
||||||
|
view->container->pending.content_x + view->geometry.x,
|
||||||
|
view->container->pending.content_y + view->geometry.y);
|
||||||
|
|
||||||
|
parent.width = view->geometry.width;
|
||||||
|
parent.height = view->geometry.height;
|
||||||
|
geo = view->geometry;
|
||||||
|
} else {
|
||||||
|
output = popup->fixed_output;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_box output_box;
|
||||||
|
wlr_output_layout_get_box(root->output_layout, output, &output_box);
|
||||||
|
|
||||||
|
bool cursor_rect = text_input->input->current.features &
|
||||||
|
WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE;
|
||||||
|
struct wlr_box cursor_area;
|
||||||
|
if (cursor_rect) {
|
||||||
|
cursor_area = text_input->input->current.cursor_rectangle;
|
||||||
|
} else {
|
||||||
|
cursor_area = (struct wlr_box) {
|
||||||
|
.width = parent.width,
|
||||||
|
.height = parent.height,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
int popup_width = popup->popup_surface->surface->current.width;
|
||||||
|
int popup_height = popup->popup_surface->surface->current.height;
|
||||||
|
int x1 = parent.x + cursor_area.x;
|
||||||
|
int x2 = parent.x + cursor_area.x + cursor_area.width;
|
||||||
|
int y1 = parent.y + cursor_area.y;
|
||||||
|
int y2 = parent.y + cursor_area.y + cursor_area.height;
|
||||||
|
int x = x1;
|
||||||
|
int y = y2;
|
||||||
|
|
||||||
|
int available_right = output_box.x + output_box.width - x1;
|
||||||
|
int available_left = x2 - output_box.x;
|
||||||
|
if (available_right < popup_width && available_left > available_right) {
|
||||||
|
x = x2 - popup_width;
|
||||||
|
}
|
||||||
|
|
||||||
|
int available_down = output_box.y + output_box.height - y2;
|
||||||
|
int available_up = y1 - output_box.y;
|
||||||
|
if (available_down < popup_height && available_up > available_down) {
|
||||||
|
y = y1 - popup_height;
|
||||||
|
}
|
||||||
|
|
||||||
|
wlr_scene_node_set_position(popup->desc.relative, x - parent.x - geo.x, y - parent.y - geo.y);
|
||||||
|
if (cursor_rect) {
|
||||||
|
struct wlr_box box = {
|
||||||
|
.x = x1 - x,
|
||||||
|
.y = y1 - y,
|
||||||
|
.width = cursor_area.width,
|
||||||
|
.height = cursor_area.height,
|
||||||
|
};
|
||||||
|
wlr_input_popup_surface_v2_send_text_input_rectangle(
|
||||||
|
popup->popup_surface, &box);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (popup->scene_tree) {
|
||||||
|
wlr_scene_node_set_position(&popup->scene_tree->node, x - geo.x, y - geo.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void input_popup_set_focus(struct sway_input_popup *popup,
|
||||||
|
struct wlr_surface *surface);
|
||||||
|
|
||||||
static void relay_send_im_state(struct sway_input_method_relay *relay,
|
static void relay_send_im_state(struct sway_input_method_relay *relay,
|
||||||
struct wlr_text_input_v3 *input) {
|
struct wlr_text_input_v3 *input) {
|
||||||
struct wlr_input_method_v2 *input_method = relay->input_method;
|
struct wlr_input_method_v2 *input_method = relay->input_method;
|
||||||
|
@ -148,10 +230,16 @@ static void relay_send_im_state(struct sway_input_method_relay *relay,
|
||||||
input->current.content_type.hint,
|
input->current.content_type.hint,
|
||||||
input->current.content_type.purpose);
|
input->current.content_type.purpose);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct sway_text_input *text_input = relay_get_focused_text_input(relay);
|
||||||
|
|
||||||
struct sway_input_popup *popup;
|
struct sway_input_popup *popup;
|
||||||
wl_list_for_each(popup, &relay->input_popups, link) {
|
wl_list_for_each(popup, &relay->input_popups, link) {
|
||||||
// send_text_input_rectangle is called in this function
|
if (text_input != NULL) {
|
||||||
input_popup_update(popup);
|
input_popup_set_focus(popup, text_input->input->focused_surface);
|
||||||
|
} else {
|
||||||
|
input_popup_set_focus(popup, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
wlr_input_method_v2_send_done(input_method);
|
wlr_input_method_v2_send_done(input_method);
|
||||||
// TODO: pass intent, display popup size
|
// TODO: pass intent, display popup size
|
||||||
|
@ -275,72 +363,76 @@ static void relay_handle_text_input(struct wl_listener *listener,
|
||||||
sway_text_input_create(relay, wlr_text_input);
|
sway_text_input_create(relay, wlr_text_input);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void input_popup_update(struct sway_input_popup *popup) {
|
static void input_popup_set_focus(struct sway_input_popup *popup,
|
||||||
struct sway_text_input *text_input =
|
struct wlr_surface *surface) {
|
||||||
relay_get_focused_text_input(popup->relay);
|
wl_list_remove(&popup->focused_surface_unmap.link);
|
||||||
|
|
||||||
if (text_input == NULL || text_input->input->focused_surface == NULL) {
|
if (!popup->scene_tree) {
|
||||||
|
wl_list_init(&popup->focused_surface_unmap.link);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (popup->scene_tree != NULL) {
|
if (popup->desc.relative) {
|
||||||
wlr_scene_node_destroy(&popup->scene_tree->node);
|
scene_descriptor_destroy(&popup->scene_tree->node, SWAY_SCENE_DESC_POPUP);
|
||||||
popup->scene_tree = NULL;
|
|
||||||
}
|
|
||||||
if (popup->desc.relative != NULL) {
|
|
||||||
wlr_scene_node_destroy(popup->desc.relative);
|
wlr_scene_node_destroy(popup->desc.relative);
|
||||||
popup->desc.relative = NULL;
|
popup->desc.relative = NULL;
|
||||||
}
|
}
|
||||||
popup->desc.view = NULL;
|
|
||||||
|
|
||||||
if (!popup->popup_surface->surface->mapped) {
|
if (surface == NULL) {
|
||||||
|
wl_list_init(&popup->focused_surface_unmap.link);
|
||||||
|
wlr_scene_node_set_enabled(&popup->scene_tree->node, false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool cursor_rect = text_input->input->current.features
|
|
||||||
& WLR_TEXT_INPUT_V3_FEATURE_CURSOR_RECTANGLE;
|
|
||||||
struct wlr_surface *focused_surface = text_input->input->focused_surface;
|
|
||||||
struct wlr_box cursor_area = text_input->input->current.cursor_rectangle;
|
|
||||||
|
|
||||||
struct wlr_box output_box;
|
|
||||||
struct wlr_box parent = {0};
|
|
||||||
struct wlr_layer_surface_v1 *layer_surface =
|
struct wlr_layer_surface_v1 *layer_surface =
|
||||||
wlr_layer_surface_v1_try_from_wlr_surface(focused_surface);
|
wlr_layer_surface_v1_try_from_wlr_surface(surface);
|
||||||
|
struct wlr_session_lock_surface_v1 *lock_surface =
|
||||||
|
wlr_session_lock_surface_v1_try_from_wlr_surface(surface);
|
||||||
|
|
||||||
struct wlr_scene_tree *relative_parent;
|
struct wlr_scene_tree *relative_parent;
|
||||||
|
if (layer_surface) {
|
||||||
|
wl_signal_add(&layer_surface->surface->events.unmap,
|
||||||
|
&popup->focused_surface_unmap);
|
||||||
|
|
||||||
struct wlr_box geo = {0};
|
struct sway_layer_surface *layer = layer_surface->data;
|
||||||
|
|
||||||
popup->scene_tree = wlr_scene_subsurface_tree_create(root->layers.popup, popup->popup_surface->surface);
|
|
||||||
if (layer_surface != NULL) {
|
|
||||||
struct sway_layer_surface *layer =
|
|
||||||
layer_surface->data;
|
|
||||||
if (layer == NULL) {
|
if (layer == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
relative_parent = layer->scene->tree;
|
relative_parent = layer->scene->tree;
|
||||||
struct wlr_output *output = layer->layer_surface->output;
|
|
||||||
wlr_output_layout_get_box(root->output_layout, output, &output_box);
|
|
||||||
int lx, ly;
|
|
||||||
wlr_scene_node_coords(&layer->tree->node, &lx, &ly);
|
|
||||||
parent.x = lx;
|
|
||||||
parent.y = ly;
|
|
||||||
popup->desc.view = NULL;
|
popup->desc.view = NULL;
|
||||||
} else {
|
|
||||||
struct sway_view *view = view_from_wlr_surface(focused_surface);
|
|
||||||
relative_parent = view->scene_tree;
|
|
||||||
geo = view->geometry;
|
|
||||||
int lx, ly;
|
|
||||||
wlr_scene_node_coords(&view->scene_tree->node, &lx, &ly);
|
|
||||||
struct wlr_output *output = wlr_output_layout_output_at(root->output_layout,
|
|
||||||
view->container->pending.content_x + view->geometry.x,
|
|
||||||
view->container->pending.content_y + view->geometry.y);
|
|
||||||
wlr_output_layout_get_box(root->output_layout, output, &output_box);
|
|
||||||
parent.x = lx;
|
|
||||||
parent.y = ly;
|
|
||||||
|
|
||||||
parent.width = view->geometry.width;
|
// we don't need to add an event here to NULL out this field because
|
||||||
parent.height = view->geometry.height;
|
// this field will only be initialized if the popup is part of a layer
|
||||||
|
// surface. Layer surfaces get destroyed as part of the output being
|
||||||
|
// destroyed, thus also trickling down to popups.
|
||||||
|
popup->fixed_output = layer->layer_surface->output;
|
||||||
|
} else if (lock_surface) {
|
||||||
|
wl_signal_add(&lock_surface->surface->events.unmap,
|
||||||
|
&popup->focused_surface_unmap);
|
||||||
|
|
||||||
|
struct sway_layer_surface *lock = lock_surface->data;
|
||||||
|
if (lock == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
relative_parent = lock->scene->tree;
|
||||||
|
popup->desc.view = NULL;
|
||||||
|
|
||||||
|
// we don't need to add an event here to NULL out this field because
|
||||||
|
// this field will only be initialized if the popup is part of a layer
|
||||||
|
// surface. Layer surfaces get destroyed as part of the output being
|
||||||
|
// destroyed, thus also trickling down to popups.
|
||||||
|
popup->fixed_output = lock->layer_surface->output;
|
||||||
|
} else {
|
||||||
|
struct sway_view *view = view_from_wlr_surface(surface);
|
||||||
|
// In the future there may be other shells been added, so we also need to check here.
|
||||||
|
if (view == NULL) {
|
||||||
|
sway_log(SWAY_DEBUG, "Unsupported IME focus surface");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
wl_signal_add(&view->events.unmap, &popup->focused_surface_unmap);
|
||||||
|
relative_parent = view->scene_tree;
|
||||||
popup->desc.view = view;
|
popup->desc.view = view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -354,93 +446,59 @@ static void input_popup_update(struct sway_input_popup *popup) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cursor_rect) {
|
constrain_popup(popup);
|
||||||
cursor_area.x = 0;
|
wlr_scene_node_set_enabled(&popup->scene_tree->node, true);
|
||||||
cursor_area.y = 0;
|
|
||||||
cursor_area.width = parent.width;
|
|
||||||
cursor_area.height = parent.height;
|
|
||||||
}
|
|
||||||
|
|
||||||
int popup_width = popup->popup_surface->surface->current.width;
|
|
||||||
int popup_height = popup->popup_surface->surface->current.height;
|
|
||||||
int x1 = parent.x + cursor_area.x;
|
|
||||||
int x2 = parent.x + cursor_area.x + cursor_area.width;
|
|
||||||
int y1 = parent.y + cursor_area.y;
|
|
||||||
int y2 = parent.y + cursor_area.y + cursor_area.height;
|
|
||||||
int x = x1;
|
|
||||||
int y = y2;
|
|
||||||
|
|
||||||
int available_right = output_box.x + output_box.width - x1;
|
|
||||||
int available_left = x2 - output_box.x;
|
|
||||||
if (available_right < popup_width && available_left > available_right) {
|
|
||||||
x = x2 - popup_width;
|
|
||||||
}
|
|
||||||
|
|
||||||
int available_down = output_box.y + output_box.height - y2;
|
|
||||||
int available_up = y1 - output_box.y;
|
|
||||||
if (available_down < popup_height && available_up > available_down) {
|
|
||||||
y = y1 - popup_height;
|
|
||||||
}
|
|
||||||
|
|
||||||
wlr_scene_node_set_position(&relative->node, x - parent.x - geo.x, y - parent.y - geo.y);
|
|
||||||
if (cursor_rect) {
|
|
||||||
struct wlr_box box = {
|
|
||||||
.x = x1 - x,
|
|
||||||
.y = y1 - y,
|
|
||||||
.width = cursor_area.width,
|
|
||||||
.height = cursor_area.height,
|
|
||||||
};
|
|
||||||
wlr_input_popup_surface_v2_send_text_input_rectangle(
|
|
||||||
popup->popup_surface, &box);
|
|
||||||
}
|
|
||||||
wlr_scene_node_set_position(&popup->scene_tree->node, x - geo.x, y - geo.y);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void input_popup_set_focus(struct sway_input_popup *popup,
|
|
||||||
struct wlr_surface *surface) {
|
|
||||||
wl_list_remove(&popup->focused_surface_unmap.link);
|
|
||||||
|
|
||||||
if (surface == NULL) {
|
|
||||||
wl_list_init(&popup->focused_surface_unmap.link);
|
|
||||||
input_popup_update(popup);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
struct wlr_layer_surface_v1 *layer_surface =
|
|
||||||
wlr_layer_surface_v1_try_from_wlr_surface(surface);
|
|
||||||
if (layer_surface != NULL) {
|
|
||||||
wl_signal_add(
|
|
||||||
&layer_surface->surface->events.unmap, &popup->focused_surface_unmap);
|
|
||||||
input_popup_update(popup);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sway_view *view = view_from_wlr_surface(surface);
|
|
||||||
wl_signal_add(&view->events.unmap, &popup->focused_surface_unmap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_im_popup_destroy(struct wl_listener *listener, void *data) {
|
static void handle_im_popup_destroy(struct wl_listener *listener, void *data) {
|
||||||
struct sway_input_popup *popup =
|
struct sway_input_popup *popup =
|
||||||
wl_container_of(listener, popup, popup_destroy);
|
wl_container_of(listener, popup, popup_destroy);
|
||||||
|
wlr_scene_node_destroy(&popup->scene_tree->node);
|
||||||
wl_list_remove(&popup->focused_surface_unmap.link);
|
wl_list_remove(&popup->focused_surface_unmap.link);
|
||||||
wl_list_remove(&popup->popup_surface_commit.link);
|
wl_list_remove(&popup->popup_surface_commit.link);
|
||||||
|
wl_list_remove(&popup->popup_surface_map.link);
|
||||||
|
wl_list_remove(&popup->popup_surface_unmap.link);
|
||||||
wl_list_remove(&popup->popup_destroy.link);
|
wl_list_remove(&popup->popup_destroy.link);
|
||||||
wl_list_remove(&popup->link);
|
wl_list_remove(&popup->link);
|
||||||
|
|
||||||
free(popup);
|
free(popup);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_im_popup_surface_commit(struct wl_listener *listener,
|
static void handle_im_popup_surface_map(struct wl_listener *listener, void *data) {
|
||||||
void *data) {
|
struct sway_input_popup *popup =
|
||||||
|
wl_container_of(listener, popup, popup_surface_map);
|
||||||
|
struct sway_text_input *text_input = relay_get_focused_text_input(popup->relay);
|
||||||
|
if (text_input != NULL) {
|
||||||
|
input_popup_set_focus(popup, text_input->input->focused_surface);
|
||||||
|
} else {
|
||||||
|
input_popup_set_focus(popup, NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_im_popup_surface_unmap(struct wl_listener *listener, void *data) {
|
||||||
|
struct sway_input_popup *popup =
|
||||||
|
wl_container_of(listener, popup, popup_surface_unmap);
|
||||||
|
|
||||||
|
scene_descriptor_destroy(&popup->scene_tree->node, SWAY_SCENE_DESC_POPUP);
|
||||||
|
// relative should already be freed as it should be a child of the just unmapped scene
|
||||||
|
popup->desc.relative = NULL;
|
||||||
|
|
||||||
|
input_popup_set_focus(popup, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void handle_im_popup_surface_commit(struct wl_listener *listener, void *data) {
|
||||||
struct sway_input_popup *popup =
|
struct sway_input_popup *popup =
|
||||||
wl_container_of(listener, popup, popup_surface_commit);
|
wl_container_of(listener, popup, popup_surface_commit);
|
||||||
input_popup_update(popup);
|
|
||||||
|
constrain_popup(popup);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_im_focused_surface_unmap(
|
static void handle_im_focused_surface_unmap(
|
||||||
struct wl_listener *listener, void *data) {
|
struct wl_listener *listener, void *data) {
|
||||||
struct sway_input_popup *popup =
|
struct sway_input_popup *popup =
|
||||||
wl_container_of(listener, popup, focused_surface_unmap);
|
wl_container_of(listener, popup, focused_surface_unmap);
|
||||||
input_popup_update(popup);
|
|
||||||
|
input_popup_set_focus(popup, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_im_new_popup_surface(struct wl_listener *listener,
|
static void handle_im_new_popup_surface(struct wl_listener *listener,
|
||||||
|
@ -448,16 +506,38 @@ static void handle_im_new_popup_surface(struct wl_listener *listener,
|
||||||
struct sway_input_method_relay *relay = wl_container_of(listener, relay,
|
struct sway_input_method_relay *relay = wl_container_of(listener, relay,
|
||||||
input_method_new_popup_surface);
|
input_method_new_popup_surface);
|
||||||
struct sway_input_popup *popup = calloc(1, sizeof(*popup));
|
struct sway_input_popup *popup = calloc(1, sizeof(*popup));
|
||||||
|
if (!popup) {
|
||||||
|
sway_log(SWAY_ERROR, "Failed to allocate an input method popup");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
popup->relay = relay;
|
popup->relay = relay;
|
||||||
popup->popup_surface = data;
|
popup->popup_surface = data;
|
||||||
popup->popup_surface->data = popup;
|
popup->popup_surface->data = popup;
|
||||||
|
|
||||||
wl_signal_add(
|
popup->scene_tree = wlr_scene_tree_create(root->layers.popup);
|
||||||
&popup->popup_surface->events.destroy, &popup->popup_destroy);
|
if (!popup->scene_tree) {
|
||||||
|
sway_log(SWAY_ERROR, "Failed to allocate scene tree");
|
||||||
|
free(popup);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!wlr_scene_subsurface_tree_create(popup->scene_tree,
|
||||||
|
popup->popup_surface->surface)) {
|
||||||
|
sway_log(SWAY_ERROR, "Failed to allocate subsurface tree");
|
||||||
|
wlr_scene_node_destroy(&popup->scene_tree->node);
|
||||||
|
free(popup);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_signal_add(&popup->popup_surface->events.destroy, &popup->popup_destroy);
|
||||||
popup->popup_destroy.notify = handle_im_popup_destroy;
|
popup->popup_destroy.notify = handle_im_popup_destroy;
|
||||||
wl_signal_add(&popup->popup_surface->surface->events.commit,
|
wl_signal_add(&popup->popup_surface->surface->events.commit, &popup->popup_surface_commit);
|
||||||
&popup->popup_surface_commit);
|
|
||||||
popup->popup_surface_commit.notify = handle_im_popup_surface_commit;
|
popup->popup_surface_commit.notify = handle_im_popup_surface_commit;
|
||||||
|
wl_signal_add(&popup->popup_surface->surface->events.map, &popup->popup_surface_map);
|
||||||
|
popup->popup_surface_map.notify = handle_im_popup_surface_map;
|
||||||
|
wl_signal_add(&popup->popup_surface->surface->events.unmap, &popup->popup_surface_unmap);
|
||||||
|
popup->popup_surface_unmap.notify = handle_im_popup_surface_unmap;
|
||||||
wl_list_init(&popup->focused_surface_unmap.link);
|
wl_list_init(&popup->focused_surface_unmap.link);
|
||||||
popup->focused_surface_unmap.notify = handle_im_focused_surface_unmap;
|
popup->focused_surface_unmap.notify = handle_im_focused_surface_unmap;
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <wlr/config.h>
|
#include <wlr/config.h>
|
||||||
#include <wlr/types/wlr_content_type_v1.h>
|
#include <wlr/types/wlr_content_type_v1.h>
|
||||||
#include <wlr/types/wlr_output.h>
|
#include <wlr/types/wlr_output.h>
|
||||||
|
#include <wlr/types/wlr_ext_foreign_toplevel_list_v1.h>
|
||||||
#include <xkbcommon/xkbcommon.h>
|
#include <xkbcommon/xkbcommon.h>
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
@ -399,6 +400,8 @@ static void ipc_json_describe_enabled_output(struct sway_output *output,
|
||||||
}
|
}
|
||||||
|
|
||||||
json_object_object_add(object, "max_render_time", json_object_new_int(output->max_render_time));
|
json_object_object_add(object, "max_render_time", json_object_new_int(output->max_render_time));
|
||||||
|
|
||||||
|
json_object_object_add(object, "allow_tearing", json_object_new_boolean(output->allow_tearing));
|
||||||
}
|
}
|
||||||
|
|
||||||
json_object *ipc_json_describe_disabled_output(struct sway_output *output) {
|
json_object *ipc_json_describe_disabled_output(struct sway_output *output) {
|
||||||
|
@ -575,6 +578,10 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object
|
||||||
json_object_object_add(object, "app_id",
|
json_object_object_add(object, "app_id",
|
||||||
app_id ? json_object_new_string(app_id) : NULL);
|
app_id ? json_object_new_string(app_id) : NULL);
|
||||||
|
|
||||||
|
json_object_object_add(object, "foreign_toplevel_identifier",
|
||||||
|
c->view->ext_foreign_toplevel ?
|
||||||
|
json_object_new_string(c->view->ext_foreign_toplevel->identifier) : NULL);
|
||||||
|
|
||||||
bool visible = view_is_visible(c->view);
|
bool visible = view_is_visible(c->view);
|
||||||
json_object_object_add(object, "visible", json_object_new_boolean(visible));
|
json_object_object_add(object, "visible", json_object_new_boolean(visible));
|
||||||
|
|
||||||
|
@ -593,11 +600,25 @@ static void ipc_json_describe_view(struct sway_container *c, json_object *object
|
||||||
|
|
||||||
json_object_object_add(object, "max_render_time", json_object_new_int(c->view->max_render_time));
|
json_object_object_add(object, "max_render_time", json_object_new_int(c->view->max_render_time));
|
||||||
|
|
||||||
|
json_object_object_add(object, "allow_tearing", json_object_new_boolean(view_can_tear(c->view)));
|
||||||
|
|
||||||
json_object_object_add(object, "shell", json_object_new_string(view_get_shell(c->view)));
|
json_object_object_add(object, "shell", json_object_new_string(view_get_shell(c->view)));
|
||||||
|
|
||||||
json_object_object_add(object, "inhibit_idle",
|
json_object_object_add(object, "inhibit_idle",
|
||||||
json_object_new_boolean(view_inhibit_idle(c->view)));
|
json_object_new_boolean(view_inhibit_idle(c->view)));
|
||||||
|
|
||||||
|
const char *sandbox_engine = view_get_sandbox_engine(c->view);
|
||||||
|
json_object_object_add(object, "sandbox_engine",
|
||||||
|
sandbox_engine ? json_object_new_string(sandbox_engine) : NULL);
|
||||||
|
|
||||||
|
const char *sandbox_app_id = view_get_sandbox_app_id(c->view);
|
||||||
|
json_object_object_add(object, "sandbox_app_id",
|
||||||
|
sandbox_app_id ? json_object_new_string(sandbox_app_id) : NULL);
|
||||||
|
|
||||||
|
const char *sandbox_instance_id = view_get_sandbox_instance_id(c->view);
|
||||||
|
json_object_object_add(object, "sandbox_instance_id",
|
||||||
|
sandbox_instance_id ? json_object_new_string(sandbox_instance_id) : NULL);
|
||||||
|
|
||||||
json_object *idle_inhibitors = json_object_new_object();
|
json_object *idle_inhibitors = json_object_new_object();
|
||||||
|
|
||||||
struct sway_idle_inhibitor_v1 *user_inhibitor =
|
struct sway_idle_inhibitor_v1 *user_inhibitor =
|
||||||
|
@ -927,6 +948,11 @@ static json_object *describe_libinput_device(struct libinput_device *device) {
|
||||||
case LIBINPUT_CONFIG_DRAG_LOCK_DISABLED:
|
case LIBINPUT_CONFIG_DRAG_LOCK_DISABLED:
|
||||||
drag_lock = "disabled";
|
drag_lock = "disabled";
|
||||||
break;
|
break;
|
||||||
|
#if HAVE_LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY
|
||||||
|
case LIBINPUT_CONFIG_DRAG_LOCK_ENABLED_STICKY:
|
||||||
|
drag_lock = "enabled_sticky";
|
||||||
|
break;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
json_object_object_add(object, "tap_drag_lock",
|
json_object_object_add(object, "tap_drag_lock",
|
||||||
json_object_new_string(drag_lock));
|
json_object_new_string(drag_lock));
|
||||||
|
@ -1129,7 +1155,9 @@ json_object *ipc_json_describe_input(struct sway_input_device *device) {
|
||||||
json_object *layouts_arr = json_object_new_array();
|
json_object *layouts_arr = json_object_new_array();
|
||||||
json_object_object_add(object, "xkb_layout_names", layouts_arr);
|
json_object_object_add(object, "xkb_layout_names", layouts_arr);
|
||||||
|
|
||||||
xkb_layout_index_t num_layouts = xkb_keymap_num_layouts(keymap);
|
xkb_layout_index_t num_layouts =
|
||||||
|
keymap ? xkb_keymap_num_layouts(keymap) : 0;
|
||||||
|
// Virtual keyboards might have null keymap
|
||||||
xkb_layout_index_t layout_idx;
|
xkb_layout_index_t layout_idx;
|
||||||
for (layout_idx = 0; layout_idx < num_layouts; layout_idx++) {
|
for (layout_idx = 0; layout_idx < num_layouts; layout_idx++) {
|
||||||
const char *layout = xkb_keymap_layout_get_name(keymap, layout_idx);
|
const char *layout = xkb_keymap_layout_get_name(keymap, layout_idx);
|
||||||
|
|
|
@ -648,6 +648,12 @@ void ipc_client_handle_command(struct ipc_client *client, uint32_t payload_lengt
|
||||||
}
|
}
|
||||||
|
|
||||||
list_t *res_list = execute_command(buf, NULL, NULL);
|
list_t *res_list = execute_command(buf, NULL, NULL);
|
||||||
|
if (modeset_is_pending()) {
|
||||||
|
// IPC expects commands to have taken immediate effect, so we need
|
||||||
|
// to force a modeset after output commands. We do a single modeset
|
||||||
|
// here to avoid modesetting for every output command in sequence.
|
||||||
|
force_modeset();
|
||||||
|
}
|
||||||
transaction_commit_dirty();
|
transaction_commit_dirty();
|
||||||
char *json = cmd_results_to_json(res_list);
|
char *json = cmd_results_to_json(res_list);
|
||||||
int length = strlen(json);
|
int length = strlen(json);
|
||||||
|
|
29
sway/lock.c
29
sway/lock.c
|
@ -8,6 +8,7 @@
|
||||||
#include "sway/layers.h"
|
#include "sway/layers.h"
|
||||||
#include "sway/output.h"
|
#include "sway/output.h"
|
||||||
#include "sway/server.h"
|
#include "sway/server.h"
|
||||||
|
#include "sway/lock.h"
|
||||||
|
|
||||||
struct sway_session_lock_output {
|
struct sway_session_lock_output {
|
||||||
struct wlr_scene_tree *tree;
|
struct wlr_scene_tree *tree;
|
||||||
|
@ -19,7 +20,6 @@ struct sway_session_lock_output {
|
||||||
struct wl_list link; // sway_session_lock::outputs
|
struct wl_list link; // sway_session_lock::outputs
|
||||||
|
|
||||||
struct wl_listener destroy;
|
struct wl_listener destroy;
|
||||||
struct wl_listener commit;
|
|
||||||
|
|
||||||
struct wlr_session_lock_surface_v1 *surface;
|
struct wlr_session_lock_surface_v1 *surface;
|
||||||
|
|
||||||
|
@ -89,6 +89,17 @@ static void lock_output_reconfigure(struct sway_session_lock_output *output) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void arrange_locks(void) {
|
||||||
|
if (server.session_lock.lock == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sway_session_lock_output *lock_output;
|
||||||
|
wl_list_for_each(lock_output, &server.session_lock.lock->outputs, link) {
|
||||||
|
lock_output_reconfigure(lock_output);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void handle_new_surface(struct wl_listener *listener, void *data) {
|
static void handle_new_surface(struct wl_listener *listener, void *data) {
|
||||||
struct sway_session_lock *lock = wl_container_of(listener, lock, new_surface);
|
struct sway_session_lock *lock = wl_container_of(listener, lock, new_surface);
|
||||||
struct wlr_session_lock_surface_v1 *lock_surface = data;
|
struct wlr_session_lock_surface_v1 *lock_surface = data;
|
||||||
|
@ -125,7 +136,6 @@ static void sway_session_lock_output_destroy(struct sway_session_lock_output *ou
|
||||||
wl_list_remove(&output->surface_map.link);
|
wl_list_remove(&output->surface_map.link);
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_list_remove(&output->commit.link);
|
|
||||||
wl_list_remove(&output->destroy.link);
|
wl_list_remove(&output->destroy.link);
|
||||||
wl_list_remove(&output->link);
|
wl_list_remove(&output->link);
|
||||||
|
|
||||||
|
@ -138,18 +148,6 @@ static void lock_node_handle_destroy(struct wl_listener *listener, void *data) {
|
||||||
sway_session_lock_output_destroy(output);
|
sway_session_lock_output_destroy(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void lock_output_handle_commit(struct wl_listener *listener, void *data) {
|
|
||||||
struct wlr_output_event_commit *event = data;
|
|
||||||
struct sway_session_lock_output *output =
|
|
||||||
wl_container_of(listener, output, commit);
|
|
||||||
if (event->state->committed & (
|
|
||||||
WLR_OUTPUT_STATE_MODE |
|
|
||||||
WLR_OUTPUT_STATE_SCALE |
|
|
||||||
WLR_OUTPUT_STATE_TRANSFORM)) {
|
|
||||||
lock_output_reconfigure(output);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct sway_session_lock_output *session_lock_output_create(
|
static struct sway_session_lock_output *session_lock_output_create(
|
||||||
struct sway_session_lock *lock, struct sway_output *output) {
|
struct sway_session_lock *lock, struct sway_output *output) {
|
||||||
struct sway_session_lock_output *lock_output = calloc(1, sizeof(*lock_output));
|
struct sway_session_lock_output *lock_output = calloc(1, sizeof(*lock_output));
|
||||||
|
@ -186,9 +184,6 @@ static struct sway_session_lock_output *session_lock_output_create(
|
||||||
lock_output->destroy.notify = lock_node_handle_destroy;
|
lock_output->destroy.notify = lock_node_handle_destroy;
|
||||||
wl_signal_add(&tree->node.events.destroy, &lock_output->destroy);
|
wl_signal_add(&tree->node.events.destroy, &lock_output->destroy);
|
||||||
|
|
||||||
lock_output->commit.notify = lock_output_handle_commit;
|
|
||||||
wl_signal_add(&output->wlr_output->events.commit, &lock_output->commit);
|
|
||||||
|
|
||||||
lock_output_reconfigure(lock_output);
|
lock_output_reconfigure(lock_output);
|
||||||
|
|
||||||
wl_list_insert(&lock->outputs, &lock_output->link);
|
wl_list_insert(&lock->outputs, &lock_output->link);
|
||||||
|
|
16
sway/main.c
16
sway/main.c
|
@ -152,6 +152,14 @@ void restore_nofile_limit(void) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void restore_signals(void) {
|
||||||
|
sigset_t set;
|
||||||
|
sigemptyset(&set);
|
||||||
|
sigprocmask(SIG_SETMASK, &set, NULL);
|
||||||
|
signal(SIGCHLD, SIG_DFL);
|
||||||
|
signal(SIGPIPE, SIG_DFL);
|
||||||
|
}
|
||||||
|
|
||||||
void enable_debug_flag(const char *flag) {
|
void enable_debug_flag(const char *flag) {
|
||||||
if (strcmp(flag, "noatomic") == 0) {
|
if (strcmp(flag, "noatomic") == 0) {
|
||||||
debug.noatomic = true;
|
debug.noatomic = true;
|
||||||
|
@ -159,8 +167,8 @@ void enable_debug_flag(const char *flag) {
|
||||||
debug.txn_wait = true;
|
debug.txn_wait = true;
|
||||||
} else if (strcmp(flag, "txn-timings") == 0) {
|
} else if (strcmp(flag, "txn-timings") == 0) {
|
||||||
debug.txn_timings = true;
|
debug.txn_timings = true;
|
||||||
} else if (strncmp(flag, "txn-timeout=", 12) == 0) {
|
} else if (has_prefix(flag, "txn-timeout=")) {
|
||||||
server.txn_timeout_ms = atoi(&flag[12]);
|
server.txn_timeout_ms = atoi(&flag[strlen("txn-timeout=")]);
|
||||||
} else if (strcmp(flag, "legacy-wl-drm") == 0) {
|
} else if (strcmp(flag, "legacy-wl-drm") == 0) {
|
||||||
debug.legacy_wl_drm = true;
|
debug.legacy_wl_drm = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -326,6 +334,9 @@ int main(int argc, char **argv) {
|
||||||
signal(SIGTERM, sig_handler);
|
signal(SIGTERM, sig_handler);
|
||||||
signal(SIGINT, sig_handler);
|
signal(SIGINT, sig_handler);
|
||||||
|
|
||||||
|
// avoid need to reap children
|
||||||
|
signal(SIGCHLD, SIG_IGN);
|
||||||
|
|
||||||
// prevent ipc from crashing sway
|
// prevent ipc from crashing sway
|
||||||
signal(SIGPIPE, SIG_IGN);
|
signal(SIGPIPE, SIG_IGN);
|
||||||
|
|
||||||
|
@ -361,6 +372,7 @@ int main(int argc, char **argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
config->active = true;
|
config->active = true;
|
||||||
|
force_modeset();
|
||||||
load_swaybars();
|
load_swaybars();
|
||||||
run_deferred_commands();
|
run_deferred_commands();
|
||||||
run_deferred_bindings();
|
run_deferred_bindings();
|
||||||
|
|
|
@ -18,6 +18,7 @@ sway_sources = files(
|
||||||
'desktop/idle_inhibit_v1.c',
|
'desktop/idle_inhibit_v1.c',
|
||||||
'desktop/layer_shell.c',
|
'desktop/layer_shell.c',
|
||||||
'desktop/output.c',
|
'desktop/output.c',
|
||||||
|
'desktop/tearing.c',
|
||||||
'desktop/transaction.c',
|
'desktop/transaction.c',
|
||||||
'desktop/xdg_shell.c',
|
'desktop/xdg_shell.c',
|
||||||
'desktop/launcher.c',
|
'desktop/launcher.c',
|
||||||
|
@ -41,6 +42,7 @@ sway_sources = files(
|
||||||
'config/seat.c',
|
'config/seat.c',
|
||||||
'config/input.c',
|
'config/input.c',
|
||||||
|
|
||||||
|
'commands/allow_tearing.c',
|
||||||
'commands/assign.c',
|
'commands/assign.c',
|
||||||
'commands/bar.c',
|
'commands/bar.c',
|
||||||
'commands/bind.c',
|
'commands/bind.c',
|
||||||
|
@ -188,6 +190,7 @@ sway_sources = files(
|
||||||
'commands/input/xkb_variant.c',
|
'commands/input/xkb_variant.c',
|
||||||
|
|
||||||
'commands/output/adaptive_sync.c',
|
'commands/output/adaptive_sync.c',
|
||||||
|
'commands/output/allow_tearing.c',
|
||||||
'commands/output/background.c',
|
'commands/output/background.c',
|
||||||
'commands/output/disable.c',
|
'commands/output/disable.c',
|
||||||
'commands/output/dpms.c',
|
'commands/output/dpms.c',
|
||||||
|
|
|
@ -39,6 +39,9 @@ void *scene_descriptor_try_get(struct wlr_scene_node *node,
|
||||||
void scene_descriptor_destroy(struct wlr_scene_node *node,
|
void scene_descriptor_destroy(struct wlr_scene_node *node,
|
||||||
enum sway_scene_descriptor_type type) {
|
enum sway_scene_descriptor_type type) {
|
||||||
struct scene_descriptor *desc = scene_node_get_descriptor(node, type);
|
struct scene_descriptor *desc = scene_node_get_descriptor(node, type);
|
||||||
|
if (!desc) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
descriptor_destroy(desc);
|
descriptor_destroy(desc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,20 +9,25 @@
|
||||||
#include <wlr/config.h>
|
#include <wlr/config.h>
|
||||||
#include <wlr/render/allocator.h>
|
#include <wlr/render/allocator.h>
|
||||||
#include <wlr/render/wlr_renderer.h>
|
#include <wlr/render/wlr_renderer.h>
|
||||||
|
#include <wlr/types/wlr_alpha_modifier_v1.h>
|
||||||
#include <wlr/types/wlr_compositor.h>
|
#include <wlr/types/wlr_compositor.h>
|
||||||
#include <wlr/types/wlr_content_type_v1.h>
|
#include <wlr/types/wlr_content_type_v1.h>
|
||||||
#include <wlr/types/wlr_cursor_shape_v1.h>
|
#include <wlr/types/wlr_cursor_shape_v1.h>
|
||||||
#include <wlr/types/wlr_data_control_v1.h>
|
#include <wlr/types/wlr_data_control_v1.h>
|
||||||
|
#include <wlr/types/wlr_ext_data_control_v1.h>
|
||||||
#include <wlr/types/wlr_data_device.h>
|
#include <wlr/types/wlr_data_device.h>
|
||||||
#include <wlr/types/wlr_drm.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_ext_foreign_toplevel_list_v1.h>
|
#include <wlr/types/wlr_ext_foreign_toplevel_list_v1.h>
|
||||||
#include <wlr/types/wlr_foreign_toplevel_management_v1.h>
|
#include <wlr/types/wlr_foreign_toplevel_management_v1.h>
|
||||||
|
#include <wlr/types/wlr_ext_image_capture_source_v1.h>
|
||||||
|
#include <wlr/types/wlr_ext_image_copy_capture_v1.h>
|
||||||
#include <wlr/types/wlr_fractional_scale_v1.h>
|
#include <wlr/types/wlr_fractional_scale_v1.h>
|
||||||
#include <wlr/types/wlr_gamma_control_v1.h>
|
#include <wlr/types/wlr_gamma_control_v1.h>
|
||||||
#include <wlr/types/wlr_idle_notify_v1.h>
|
#include <wlr/types/wlr_idle_notify_v1.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_linux_dmabuf_v1.h>
|
||||||
|
#include <wlr/types/wlr_linux_drm_syncobj_v1.h>
|
||||||
#include <wlr/types/wlr_output_management_v1.h>
|
#include <wlr/types/wlr_output_management_v1.h>
|
||||||
#include <wlr/types/wlr_output_power_management_v1.h>
|
#include <wlr/types/wlr_output_power_management_v1.h>
|
||||||
#include <wlr/types/wlr_pointer_constraints_v1.h>
|
#include <wlr/types/wlr_pointer_constraints_v1.h>
|
||||||
|
@ -68,6 +73,7 @@
|
||||||
#define SWAY_XDG_SHELL_VERSION 5
|
#define SWAY_XDG_SHELL_VERSION 5
|
||||||
#define SWAY_LAYER_SHELL_VERSION 4
|
#define SWAY_LAYER_SHELL_VERSION 4
|
||||||
#define SWAY_FOREIGN_TOPLEVEL_LIST_VERSION 1
|
#define SWAY_FOREIGN_TOPLEVEL_LIST_VERSION 1
|
||||||
|
#define SWAY_PRESENTATION_VERSION 2
|
||||||
|
|
||||||
bool allow_unsupported_gpu = false;
|
bool allow_unsupported_gpu = false;
|
||||||
|
|
||||||
|
@ -103,8 +109,10 @@ static bool is_privileged(const struct wl_global *global) {
|
||||||
global == server.input_method->global ||
|
global == server.input_method->global ||
|
||||||
global == server.foreign_toplevel_list->global ||
|
global == server.foreign_toplevel_list->global ||
|
||||||
global == server.foreign_toplevel_manager->global ||
|
global == server.foreign_toplevel_manager->global ||
|
||||||
global == server.data_control_manager_v1->global ||
|
global == server.wlr_data_control_manager_v1->global ||
|
||||||
|
global == server.ext_data_control_manager_v1->global ||
|
||||||
global == server.screencopy_manager_v1->global ||
|
global == server.screencopy_manager_v1->global ||
|
||||||
|
global == server.ext_image_copy_capture_manager_v1->global ||
|
||||||
global == server.export_dmabuf_manager_v1->global ||
|
global == server.export_dmabuf_manager_v1->global ||
|
||||||
global == server.security_context_manager_v1->global ||
|
global == server.security_context_manager_v1->global ||
|
||||||
global == server.gamma_control_manager_v1->global ||
|
global == server.gamma_control_manager_v1->global ||
|
||||||
|
@ -203,8 +211,8 @@ static void handle_renderer_lost(struct wl_listener *listener, void *data) {
|
||||||
|
|
||||||
wlr_compositor_set_renderer(server->compositor, renderer);
|
wlr_compositor_set_renderer(server->compositor, renderer);
|
||||||
|
|
||||||
for (int i = 0; i < root->outputs->length; ++i) {
|
struct sway_output *output;
|
||||||
struct sway_output *output = root->outputs->items[i];
|
wl_list_for_each(output, &root->all_outputs, link) {
|
||||||
wlr_output_init_render(output->wlr_output,
|
wlr_output_init_render(output->wlr_output,
|
||||||
server->allocator, server->renderer);
|
server->allocator, server->renderer);
|
||||||
}
|
}
|
||||||
|
@ -219,6 +227,7 @@ bool server_init(struct sway_server *server) {
|
||||||
server->wl_event_loop = wl_display_get_event_loop(server->wl_display);
|
server->wl_event_loop = wl_display_get_event_loop(server->wl_display);
|
||||||
|
|
||||||
wl_display_set_global_filter(server->wl_display, filter_global, NULL);
|
wl_display_set_global_filter(server->wl_display, filter_global, NULL);
|
||||||
|
wl_display_set_default_max_buffer_size(server->wl_display, 1024 * 1024);
|
||||||
|
|
||||||
root = root_create(server->wl_display);
|
root = root_create(server->wl_display);
|
||||||
|
|
||||||
|
@ -248,6 +257,12 @@ bool server_init(struct sway_server *server) {
|
||||||
wlr_drm_create(server->wl_display, server->renderer);
|
wlr_drm_create(server->wl_display, server->renderer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (wlr_renderer_get_drm_fd(server->renderer) >= 0 &&
|
||||||
|
server->renderer->features.timeline &&
|
||||||
|
server->backend->features.timeline) {
|
||||||
|
wlr_linux_drm_syncobj_manager_v1_create(server->wl_display, 1,
|
||||||
|
wlr_renderer_get_drm_fd(server->renderer));
|
||||||
|
}
|
||||||
|
|
||||||
server->allocator = wlr_allocator_autocreate(server->backend,
|
server->allocator = wlr_allocator_autocreate(server->backend,
|
||||||
server->renderer);
|
server->renderer);
|
||||||
|
@ -266,15 +281,11 @@ bool server_init(struct sway_server *server) {
|
||||||
|
|
||||||
server->gamma_control_manager_v1 =
|
server->gamma_control_manager_v1 =
|
||||||
wlr_gamma_control_manager_v1_create(server->wl_display);
|
wlr_gamma_control_manager_v1_create(server->wl_display);
|
||||||
server->gamma_control_set_gamma.notify = handle_gamma_control_set_gamma;
|
wlr_scene_set_gamma_control_manager_v1(root->root_scene,
|
||||||
wl_signal_add(&server->gamma_control_manager_v1->events.set_gamma,
|
server->gamma_control_manager_v1);
|
||||||
&server->gamma_control_set_gamma);
|
|
||||||
|
|
||||||
server->new_output.notify = handle_new_output;
|
server->new_output.notify = handle_new_output;
|
||||||
wl_signal_add(&server->backend->events.new_output, &server->new_output);
|
wl_signal_add(&server->backend->events.new_output, &server->new_output);
|
||||||
server->output_layout_change.notify = handle_output_layout_change;
|
|
||||||
wl_signal_add(&root->output_layout->events.change,
|
|
||||||
&server->output_layout_change);
|
|
||||||
|
|
||||||
server->xdg_output_manager_v1 =
|
server->xdg_output_manager_v1 =
|
||||||
wlr_xdg_output_manager_v1_create(server->wl_display, root->output_layout);
|
wlr_xdg_output_manager_v1_create(server->wl_display, root->output_layout);
|
||||||
|
@ -323,7 +334,8 @@ bool server_init(struct sway_server *server) {
|
||||||
wl_signal_add(&server->pointer_constraints->events.new_constraint,
|
wl_signal_add(&server->pointer_constraints->events.new_constraint,
|
||||||
&server->pointer_constraint);
|
&server->pointer_constraint);
|
||||||
|
|
||||||
wlr_presentation_create(server->wl_display, server->backend);
|
wlr_presentation_create(server->wl_display, server->backend, SWAY_PRESENTATION_VERSION);
|
||||||
|
wlr_alpha_modifier_v1_create(server->wl_display);
|
||||||
|
|
||||||
server->output_manager_v1 =
|
server->output_manager_v1 =
|
||||||
wlr_output_manager_v1_create(server->wl_display);
|
wlr_output_manager_v1_create(server->wl_display);
|
||||||
|
@ -364,7 +376,10 @@ bool server_init(struct sway_server *server) {
|
||||||
|
|
||||||
server->export_dmabuf_manager_v1 = wlr_export_dmabuf_manager_v1_create(server->wl_display);
|
server->export_dmabuf_manager_v1 = wlr_export_dmabuf_manager_v1_create(server->wl_display);
|
||||||
server->screencopy_manager_v1 = wlr_screencopy_manager_v1_create(server->wl_display);
|
server->screencopy_manager_v1 = wlr_screencopy_manager_v1_create(server->wl_display);
|
||||||
server->data_control_manager_v1 = wlr_data_control_manager_v1_create(server->wl_display);
|
server->ext_image_copy_capture_manager_v1 = wlr_ext_image_copy_capture_manager_v1_create(server->wl_display, 1);
|
||||||
|
wlr_ext_output_image_capture_source_manager_v1_create(server->wl_display, 1);
|
||||||
|
server->wlr_data_control_manager_v1 = wlr_data_control_manager_v1_create(server->wl_display);
|
||||||
|
server->ext_data_control_manager_v1 = wlr_ext_data_control_manager_v1_create(server->wl_display, 1);
|
||||||
server->security_context_manager_v1 = wlr_security_context_manager_v1_create(server->wl_display);
|
server->security_context_manager_v1 = wlr_security_context_manager_v1_create(server->wl_display);
|
||||||
wlr_viewporter_create(server->wl_display);
|
wlr_viewporter_create(server->wl_display);
|
||||||
wlr_single_pixel_buffer_manager_v1_create(server->wl_display);
|
wlr_single_pixel_buffer_manager_v1_create(server->wl_display);
|
||||||
|
@ -372,6 +387,13 @@ bool server_init(struct sway_server *server) {
|
||||||
wlr_content_type_manager_v1_create(server->wl_display, 1);
|
wlr_content_type_manager_v1_create(server->wl_display, 1);
|
||||||
wlr_fractional_scale_manager_v1_create(server->wl_display, 1);
|
wlr_fractional_scale_manager_v1_create(server->wl_display, 1);
|
||||||
|
|
||||||
|
server->tearing_control_v1 =
|
||||||
|
wlr_tearing_control_manager_v1_create(server->wl_display, 1);
|
||||||
|
server->tearing_control_new_object.notify = handle_new_tearing_hint;
|
||||||
|
wl_signal_add(&server->tearing_control_v1->events.new_object,
|
||||||
|
&server->tearing_control_new_object);
|
||||||
|
wl_list_init(&server->tearing_controllers);
|
||||||
|
|
||||||
struct wlr_xdg_foreign_registry *foreign_registry =
|
struct wlr_xdg_foreign_registry *foreign_registry =
|
||||||
wlr_xdg_foreign_registry_create(server->wl_display);
|
wlr_xdg_foreign_registry_create(server->wl_display);
|
||||||
wlr_xdg_foreign_v1_create(server->wl_display, foreign_registry);
|
wlr_xdg_foreign_v1_create(server->wl_display, foreign_registry);
|
||||||
|
|
|
@ -143,6 +143,12 @@ runtime.
|
||||||
|
|
||||||
This setting also applies to the current binding mode indicator.
|
This setting also applies to the current binding mode indicator.
|
||||||
|
|
||||||
|
The following commands may only be used at runtime.
|
||||||
|
|
||||||
|
*mode* toggle [<bar_id>]
|
||||||
|
Toggles the current mode between _hide_ and _dock_. Any other mode
|
||||||
|
is treated as _hide_.
|
||||||
|
|
||||||
## TRAY
|
## TRAY
|
||||||
|
|
||||||
Swaybar provides a system tray where third-party applications may place icons.
|
Swaybar provides a system tray where third-party applications may place icons.
|
||||||
|
|
|
@ -152,8 +152,9 @@ The following commands may only be used in the configuration file.
|
||||||
*input* <identifier> drag enabled|disabled
|
*input* <identifier> drag enabled|disabled
|
||||||
Enables or disables tap-and-drag for specified input device.
|
Enables or disables tap-and-drag for specified input device.
|
||||||
|
|
||||||
*input* <identifier> drag_lock enabled|disabled
|
*input* <identifier> drag_lock enabled|disabled|enabled_sticky
|
||||||
Enables or disables drag lock for specified input device.
|
Enables or disables drag lock for specified input device. The default is
|
||||||
|
_enabled_sticky_.
|
||||||
|
|
||||||
*input* <identifier> dwt enabled|disabled
|
*input* <identifier> dwt enabled|disabled
|
||||||
Enables or disables disable-while-typing for the specified input device.
|
Enables or disables disable-while-typing for the specified input device.
|
||||||
|
|
|
@ -138,7 +138,7 @@ has the following properties:
|
||||||
: Whether the workspace is currently focused by the default seat (_seat0_)
|
: Whether the workspace is currently focused by the default seat (_seat0_)
|
||||||
|- urgent
|
|- urgent
|
||||||
: boolean
|
: boolean
|
||||||
: Whether a view on the workspace has the urgent flag set
|
: Whether a window on the workspace has the urgent flag set
|
||||||
|- rect
|
|- rect
|
||||||
: object
|
: object
|
||||||
: The bounds of the workspace. It consists of _x_, _y_, _width_, and _height_
|
: The bounds of the workspace. It consists of _x_, _y_, _width_, and _height_
|
||||||
|
@ -374,7 +374,7 @@ node and will have the following properties:
|
||||||
that can be used as an aid in submitting reproduction steps for bug reports
|
that can be used as an aid in submitting reproduction steps for bug reports
|
||||||
|- fullscreen_mode
|
|- fullscreen_mode
|
||||||
: integer
|
: integer
|
||||||
: (Only containers and views) The fullscreen mode of the node. 0 means none, 1 means
|
: (Only containers and windows) The fullscreen mode of the node. 0 means none, 1 means
|
||||||
full workspace, and 2 means global fullscreen
|
full workspace, and 2 means global fullscreen
|
||||||
|- floating
|
|- floating
|
||||||
: string
|
: string
|
||||||
|
@ -384,32 +384,45 @@ node and will have the following properties:
|
||||||
: Whether the window is in the scratchpad. Can be either "none" or "fresh"
|
: Whether the window is in the scratchpad. Can be either "none" or "fresh"
|
||||||
|- app_id
|
|- app_id
|
||||||
: string
|
: string
|
||||||
: (Only views) For an xdg-shell view, the name of the application, if set.
|
: (Only windows) For an xdg-shell window, the name of the application, if set.
|
||||||
Otherwise, _null_
|
Otherwise, _null_
|
||||||
|- pid
|
|- pid
|
||||||
: integer
|
: integer
|
||||||
: (Only views) The PID of the application that owns the view
|
: (Only windows) The PID of the application that owns the window
|
||||||
|
|- foreign_toplevel_identifier
|
||||||
|
: string
|
||||||
|
: (Only windows) The ext-foreign-toplevel-list-v1 toplevel identifier of this node.
|
||||||
|- visible
|
|- visible
|
||||||
: boolean
|
: boolean
|
||||||
: (Only views) Whether the node is visible
|
: (Only windows) Whether the node is visible
|
||||||
|- shell
|
|- shell
|
||||||
: string
|
: string
|
||||||
: (Only views) The shell of the view, such as _xdg\_shell_ or _xwayland_
|
: (Only windows) The shell of the window, such as _xdg\_shell_ or _xwayland_
|
||||||
|- inhibit_idle
|
|- inhibit_idle
|
||||||
: boolean
|
: boolean
|
||||||
: (Only views) Whether the view is inhibiting the idle state
|
: (Only windows) Whether the window is inhibiting the idle state
|
||||||
|- idle_inhibitors
|
|- idle_inhibitors
|
||||||
: object
|
: object
|
||||||
: (Only views) An object containing the state of the _application_ and _user_ idle inhibitors.
|
: (Only windows) An object containing the state of the _application_ and _user_ idle inhibitors.
|
||||||
_application_ can be _enabled_ or _none_.
|
_application_ can be _enabled_ or _none_.
|
||||||
_user_ can be _focus_, _fullscreen_, _open_, _visible_ or _none_.
|
_user_ can be _focus_, _fullscreen_, _open_, _visible_ or _none_.
|
||||||
|
|- sandbox_engine
|
||||||
|
: string
|
||||||
|
: (Only windows) The associated sandbox engine (or _null_)
|
||||||
|
|- sandbox_app_id
|
||||||
|
: string
|
||||||
|
: (Only windows) The app ID provided by the associated sandbox engine (or _null_)
|
||||||
|
|- sandbox_instance_id
|
||||||
|
: string
|
||||||
|
: (Only windows) The instance ID provided by the associated sandbox engine (or
|
||||||
|
_null_)
|
||||||
|- window
|
|- window
|
||||||
: integer
|
: integer
|
||||||
: (Only xwayland views) The X11 window ID for the xwayland view
|
: (Only xwayland windows) The X11 window ID for the xwayland window
|
||||||
|- window_properties
|
|- window_properties
|
||||||
: object
|
: object
|
||||||
: (Only xwayland views) An object containing the _title_, _class_, _instance_,
|
: (Only xwayland windows) An object containing the _title_, _class_, _instance_,
|
||||||
_window\_role_, _window\_type_, and _transient\_for_ for the view
|
_window\_role_, _window\_type_, and _transient\_for_ for the window
|
||||||
|
|
||||||
|
|
||||||
*Example Reply:*
|
*Example Reply:*
|
||||||
|
@ -914,13 +927,13 @@ containing the _#RRGGBBAA_ representation of the color:
|
||||||
that are not visible
|
that are not visible
|
||||||
|- urgent_workspace_text
|
|- urgent_workspace_text
|
||||||
: The color to use for the text of the workspace buttons for workspaces that
|
: The color to use for the text of the workspace buttons for workspaces that
|
||||||
contain an urgent view
|
contain an urgent window
|
||||||
|- urgent_workspace_bg
|
|- urgent_workspace_bg
|
||||||
: The color to use for the background of the workspace buttons for workspaces
|
: The color to use for the background of the workspace buttons for workspaces
|
||||||
that contain an urgent view
|
that contain an urgent window
|
||||||
|- urgent_workspace_border
|
|- urgent_workspace_border
|
||||||
: The color to use for the border of the workspace buttons for workspaces that
|
: The color to use for the border of the workspace buttons for workspaces that
|
||||||
contain an urgent view
|
contain an urgent window
|
||||||
|- binding_mode_text
|
|- binding_mode_text
|
||||||
: The color to use for the text of the binding mode indicator
|
: The color to use for the text of the binding mode indicator
|
||||||
|- binding_mode_bg
|
|- binding_mode_bg
|
||||||
|
@ -1174,7 +1187,8 @@ following properties will be included for devices that support them:
|
||||||
: Whether tap-and-drag is enabled. It can be _enabled_ or _disabled_
|
: Whether tap-and-drag is enabled. It can be _enabled_ or _disabled_
|
||||||
|- tap_drag_lock
|
|- tap_drag_lock
|
||||||
: string
|
: string
|
||||||
: Whether drag-lock is enabled. It can be _enabled_ or _disabled_
|
: Whether drag-lock is enabled. It can be _enabled_, _disabled_ or
|
||||||
|
_enabled_sticky_
|
||||||
|- accel_speed
|
|- accel_speed
|
||||||
: double
|
: double
|
||||||
: The pointer-acceleration in use
|
: The pointer-acceleration in use
|
||||||
|
@ -1466,7 +1480,7 @@ available:
|
||||||
: Sent whenever the binding mode changes
|
: Sent whenever the binding mode changes
|
||||||
|- 0x80000003
|
|- 0x80000003
|
||||||
: window
|
: window
|
||||||
: Sent whenever an event involving a view occurs such as being reparented,
|
: Sent whenever an event involving a window occurs such as being reparented,
|
||||||
focused, or closed
|
focused, or closed
|
||||||
|- 0x80000004
|
|- 0x80000004
|
||||||
: barconfig_update
|
: barconfig_update
|
||||||
|
@ -1522,8 +1536,8 @@ The following change types are currently available:
|
||||||
|- rename
|
|- rename
|
||||||
: The workspace was renamed
|
: The workspace was renamed
|
||||||
|- urgent
|
|- urgent
|
||||||
: A view on the workspace has had their urgency hint set or all urgency hints
|
: A window on the workspace has had their urgency hint set or all urgency hints
|
||||||
for views on the workspace have been cleared
|
for windows on the workspace have been cleared
|
||||||
|- reload
|
|- reload
|
||||||
: The configuration file has been reloaded
|
: The configuration file has been reloaded
|
||||||
|
|
||||||
|
@ -1621,7 +1635,7 @@ with the following properties:
|
||||||
|
|
||||||
## 0x80000003. WINDOW
|
## 0x80000003. WINDOW
|
||||||
|
|
||||||
Sent whenever a change involving a view occurs. The event consists of a single
|
Sent whenever a change involving a window occurs. The event consists of a single
|
||||||
object with the following properties:
|
object with the following properties:
|
||||||
|
|
||||||
[- *PROPERTY*
|
[- *PROPERTY*
|
||||||
|
@ -1632,30 +1646,30 @@ object with the following properties:
|
||||||
:[ The type of change that occurred. See below for more information
|
:[ The type of change that occurred. See below for more information
|
||||||
|- container
|
|- container
|
||||||
: object
|
: object
|
||||||
: An object representing the view effected
|
: An object representing the window effected
|
||||||
|
|
||||||
|
|
||||||
The following change types are currently available:
|
The following change types are currently available:
|
||||||
[- *TYPE*
|
[- *TYPE*
|
||||||
:- *DESCRIPTION*
|
:- *DESCRIPTION*
|
||||||
|- new
|
|- new
|
||||||
:[ The view was created
|
:[ The window was created
|
||||||
|- close
|
|- close
|
||||||
: The view was closed
|
: The window was closed
|
||||||
|- focus
|
|- focus
|
||||||
: The view was focused
|
: The window was focused
|
||||||
|- title
|
|- title
|
||||||
: The view's title has changed
|
: The window's title has changed
|
||||||
|- fullscreen_mode
|
|- fullscreen_mode
|
||||||
: The view's fullscreen mode has changed
|
: The window's fullscreen mode has changed
|
||||||
|- move
|
|- move
|
||||||
: The view has been reparented in the tree
|
: The window has been reparented in the tree
|
||||||
|- floating
|
|- floating
|
||||||
: The view has become floating or is no longer floating
|
: The window has become floating or is no longer floating
|
||||||
|- urgent
|
|- urgent
|
||||||
: The view's urgency hint has changed status
|
: The window's urgency hint has changed status
|
||||||
|- mark
|
|- mark
|
||||||
: A mark has been added or removed from the view
|
: A mark has been added or removed from the window
|
||||||
|
|
||||||
|
|
||||||
*Example Event:*
|
*Example Event:*
|
||||||
|
|
|
@ -154,7 +154,7 @@ must be separated by one space. For example:
|
||||||
This setting only has an effect on Wayland and DRM backends, as support for
|
This setting only has an effect on Wayland and DRM backends, as support for
|
||||||
presentation timestamps and predicted output refresh rate is required.
|
presentation timestamps and predicted output refresh rate is required.
|
||||||
|
|
||||||
*output* <name> adaptive_sync on|off
|
*output* <name> adaptive_sync on|off|toggle
|
||||||
Enables or disables adaptive synchronization (often referred to as Variable
|
Enables or disables adaptive synchronization (often referred to as Variable
|
||||||
Refresh Rate, or by the vendor-specific names FreeSync/G-Sync).
|
Refresh Rate, or by the vendor-specific names FreeSync/G-Sync).
|
||||||
|
|
||||||
|
@ -163,9 +163,9 @@ 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
|
*output* <name> render_bit_depth 6|8|10
|
||||||
Controls the color channel bit depth at which frames are rendered; the
|
Controls the maximum color channel bit depth at which frames are
|
||||||
default is currently 8 bits per channel.
|
rendered; the default is currently 8 bits per channel.
|
||||||
|
|
||||||
Setting higher values will not have an effect if hardware and software lack
|
Setting higher values will not have an effect if hardware and software lack
|
||||||
support for such bit depths. Successfully increasing the render bit depth
|
support for such bit depths. Successfully increasing the render bit depth
|
||||||
|
@ -190,6 +190,26 @@ must be separated by one space. For example:
|
||||||
may have no effect or produce unexpected output when used together with future
|
may have no effect or produce unexpected output when used together with future
|
||||||
HDR support features.
|
HDR support features.
|
||||||
|
|
||||||
|
*output* <name> allow_tearing yes|no
|
||||||
|
Allows or disallows screen tearing as a result of immediate page flips,
|
||||||
|
and an immediate presentation mode from a client. The default is that no
|
||||||
|
screen tearing is allowed.
|
||||||
|
|
||||||
|
With immediate page flips, frames from the client are presented as soon
|
||||||
|
as possible instead of synchronizing with the monitor's vblank interval
|
||||||
|
(VSync).
|
||||||
|
|
||||||
|
It is recommended to set *max_render_time* to *off*. In that case a page flip
|
||||||
|
happens as soon as a client updates. Otherwise, tearing will only happen if
|
||||||
|
rendering takes longer than the configured milliseconds before the next
|
||||||
|
display refresh.
|
||||||
|
|
||||||
|
To adjust whether tearing is allowed for specific applications, see
|
||||||
|
*allow_tearing* in *sway*(5). Note that tearing will only be enabled
|
||||||
|
when it's allowed for both the output and the application.
|
||||||
|
|
||||||
|
This setting only has effect when a window is fullscreen on the output.
|
||||||
|
|
||||||
# SEE ALSO
|
# SEE ALSO
|
||||||
|
|
||||||
*sway*(5) *sway-input*(5)
|
*sway*(5) *sway-input*(5)
|
||||||
|
|
154
sway/sway.5.scd
154
sway/sway.5.scd
|
@ -57,6 +57,7 @@ which you may only select one. *[...]* is used for optional arguments, and
|
||||||
This section only lists general commands. For input and output commands, refer
|
This section only lists general commands. For input and output commands, refer
|
||||||
to *sway-input*(5) and *sway-output*(5).
|
to *sway-input*(5) and *sway-output*(5).
|
||||||
|
|
||||||
|
## Config only commands
|
||||||
The following commands may only be used in the configuration file.
|
The following commands may only be used in the configuration file.
|
||||||
|
|
||||||
*bar* [<bar-id>] <bar-subcommands...>
|
*bar* [<bar-id>] <bar-subcommands...>
|
||||||
|
@ -65,8 +66,8 @@ The following commands may only be used in the configuration file.
|
||||||
*default_orientation* horizontal|vertical|auto
|
*default_orientation* horizontal|vertical|auto
|
||||||
Sets the default container layout for tiled containers.
|
Sets the default container layout for tiled containers.
|
||||||
|
|
||||||
*include* <path>
|
*include* <paths...>
|
||||||
Includes another file from _path_. _path_ can be either a full path or a
|
Include files from _paths_. _paths_ can include either a full path or a
|
||||||
path relative to the parent config, and expands shell syntax (see
|
path relative to the parent config, and expands shell syntax (see
|
||||||
*wordexp*(3) for details). The same include file can only be included once;
|
*wordexp*(3) for details). The same include file can only be included once;
|
||||||
subsequent attempts will be ignored.
|
subsequent attempts will be ignored.
|
||||||
|
@ -98,15 +99,16 @@ The following commands may only be used in the configuration file.
|
||||||
machines, it may be desirable to have Xwayland started immediately by
|
machines, it may be desirable to have Xwayland started immediately by
|
||||||
using _force_ instead of _enable_.
|
using _force_ instead of _enable_.
|
||||||
|
|
||||||
|
## Runtime only commands
|
||||||
The following commands cannot be used directly in the configuration file.
|
The following commands cannot be used directly in the configuration file.
|
||||||
They are expected to be used with *bindsym* or at runtime through *swaymsg*(1).
|
They are expected to be used with *bindsym* or at runtime through *swaymsg*(1).
|
||||||
|
|
||||||
*border* none|normal|csd|pixel [<n>]
|
*border* none|normal|csd|pixel [<n>]
|
||||||
Set border style for focused window. _normal_ includes a border of
|
Set border style for focused window. _normal_ includes a border of
|
||||||
thickness _n_ and a title bar. _pixel_ is a border without title bar _n_
|
thickness _n_ and a title bar. _pixel_ is a border without title bar _n_
|
||||||
pixels thick. Default is _normal_ with border thickness 2. _csd_ is short
|
pixels thick. The title bar always shows in stacking or tabbed layouts.
|
||||||
for client-side-decorations, which allows the client to draw its own
|
_csd_ is short for client-side-decorations, which allows the client to draw
|
||||||
decorations.
|
its own decorations. Default is _normal_ with border thickness 2.
|
||||||
|
|
||||||
*border* toggle
|
*border* toggle
|
||||||
Cycles through the available border styles.
|
Cycles through the available border styles.
|
||||||
|
@ -115,7 +117,7 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1).
|
||||||
Exit sway and end your Wayland session.
|
Exit sway and end your Wayland session.
|
||||||
|
|
||||||
*floating* enable|disable|toggle
|
*floating* enable|disable|toggle
|
||||||
Make focused view floating, non-floating, or the opposite of what it is now.
|
Make focused window floating, non-floating, or the opposite of what it is now.
|
||||||
|
|
||||||
<criteria> *focus*
|
<criteria> *focus*
|
||||||
Moves focus to the container that matches the specified criteria.
|
Moves focus to the container that matches the specified criteria.
|
||||||
|
@ -150,9 +152,9 @@ They are expected to be used with *bindsym* or at runtime through *swaymsg*(1).
|
||||||
Moves focus between the floating and tiled layers.
|
Moves focus between the floating and tiled layers.
|
||||||
|
|
||||||
*fullscreen* [enable|disable|toggle] [global]
|
*fullscreen* [enable|disable|toggle] [global]
|
||||||
Makes focused view fullscreen, non-fullscreen, or the opposite of what it
|
Makes focused window fullscreen, non-fullscreen, or the opposite of what it
|
||||||
is now. If no argument is given, it does the same as _toggle_. If _global_
|
is now. If no argument is given, it does the same as _toggle_. If _global_
|
||||||
is specified, the view will be fullscreen across all outputs.
|
is specified, the window will be fullscreen across all outputs.
|
||||||
|
|
||||||
*gaps* inner|outer|horizontal|vertical|top|right|bottom|left all|current
|
*gaps* inner|outer|horizontal|vertical|top|right|bottom|left all|current
|
||||||
set|plus|minus|toggle <amount>
|
set|plus|minus|toggle <amount>
|
||||||
|
@ -162,16 +164,16 @@ set|plus|minus|toggle <amount>
|
||||||
_vertical_.
|
_vertical_.
|
||||||
|
|
||||||
*inhibit_idle* focus|fullscreen|open|none|visible
|
*inhibit_idle* focus|fullscreen|open|none|visible
|
||||||
Set/unset an idle inhibitor for the view. _focus_ will inhibit idle when
|
Set/unset an idle inhibitor for the window. _focus_ will inhibit idle when
|
||||||
the view is focused by any seat. _fullscreen_ will inhibit idle when the
|
the window is focused by any seat. _fullscreen_ will inhibit idle when the
|
||||||
view is fullscreen (or a descendant of a fullscreen container) and is
|
view is fullscreen (or a descendant of a fullscreen container) and is
|
||||||
visible. _open_ will inhibit idle until the view is closed (or the
|
visible. _open_ will inhibit idle until the window is closed (or the
|
||||||
inhibitor is unset/changed). _visible_ will inhibit idle when the view is
|
inhibitor is unset/changed). _visible_ will inhibit idle when the window is
|
||||||
visible on any output. _none_ will remove any existing idle inhibitor for
|
visible on any output. _none_ will remove any existing idle inhibitor for
|
||||||
the view.
|
the window.
|
||||||
|
|
||||||
This can also be used with criteria to set an idle inhibitor for any
|
This can also be used with criteria to set an idle inhibitor for any
|
||||||
existing view or with _for_window_ to set idle inhibitors for future views.
|
existing window or with _for_window_ to set idle inhibitors for future windows.
|
||||||
|
|
||||||
*layout* default|splith|splitv|stacking|tabbed
|
*layout* default|splith|splitv|stacking|tabbed
|
||||||
Sets the layout mode of the focused container.
|
Sets the layout mode of the focused container.
|
||||||
|
@ -215,6 +217,20 @@ set|plus|minus|toggle <amount>
|
||||||
effect on the output the window is currently on. See *sway-output*(5) for
|
effect on the output the window is currently on. See *sway-output*(5) for
|
||||||
further details.
|
further details.
|
||||||
|
|
||||||
|
*allow_tearing* yes|no
|
||||||
|
Allows or disallows screen tearing as a result of immediate page flips
|
||||||
|
for a fullscreen application.
|
||||||
|
|
||||||
|
When this option is not set, the tearing hints provided by the application
|
||||||
|
determine whether tearing is allowed. When _yes_ is specified,
|
||||||
|
the application allows tearing regardless of the tearing hints.
|
||||||
|
When _no_ is specified, tearing will never be allowed on the application,
|
||||||
|
regardless of the tearing hints.
|
||||||
|
|
||||||
|
This setting only has an effect if tearing is allowed on the output through
|
||||||
|
the per-output *allow_tearing* setting. See *sway-output*(5)
|
||||||
|
for further details.
|
||||||
|
|
||||||
*move* left|right|up|down [<px> px]
|
*move* left|right|up|down [<px> px]
|
||||||
Moves the focused container in the direction specified. The optional _px_
|
Moves the focused container in the direction specified. The optional _px_
|
||||||
argument specifies how many pixels to move the container. If unspecified,
|
argument specifies how many pixels to move the container. If unspecified,
|
||||||
|
@ -315,12 +331,12 @@ set|plus|minus|toggle <amount>
|
||||||
|
|
||||||
*shortcuts_inhibitor* enable|disable
|
*shortcuts_inhibitor* enable|disable
|
||||||
Enables or disables the ability of clients to inhibit keyboard
|
Enables or disables the ability of clients to inhibit keyboard
|
||||||
shortcuts for a view. This is primarily useful for virtualization and
|
shortcuts for a window. This is primarily useful for virtualization and
|
||||||
remote desktop software. It affects either the currently focused view
|
remote desktop software. It affects either the currently focused window
|
||||||
or a set of views selected by criteria. Subcommand _disable_
|
or a set of windows selected by criteria. Subcommand _disable_
|
||||||
additionally deactivates any active inhibitors for the given view(s).
|
additionally deactivates any active inhibitors for the given window(s).
|
||||||
Criteria are particularly useful with the *for_window* command to
|
Criteria are particularly useful with the *for_window* command to
|
||||||
configure a class of views differently from the per-seat defaults
|
configure a class of windows differently from the per-seat defaults
|
||||||
established by the *seat* subcommand of the same name. See
|
established by the *seat* subcommand of the same name. See
|
||||||
*sway-input*(5) for more ways to affect inhibitors.
|
*sway-input*(5) for more ways to affect inhibitors.
|
||||||
|
|
||||||
|
@ -348,7 +364,7 @@ set|plus|minus|toggle <amount>
|
||||||
Swaps the position, geometry, and fullscreen status of two containers. The
|
Swaps the position, geometry, and fullscreen status of two containers. The
|
||||||
first container can be selected either by criteria or focus. The second
|
first container can be selected either by criteria or focus. The second
|
||||||
container can be selected by _id_, _con_id_, or _mark_. _id_ can only be
|
container can be selected by _id_, _con_id_, or _mark_. _id_ can only be
|
||||||
used with xwayland views. If the first container has focus, it will retain
|
used with xwayland windows. If the first container has focus, it will retain
|
||||||
focus unless it is moved to a different workspace or the second container
|
focus unless it is moved to a different workspace or the second container
|
||||||
becomes fullscreen on the same workspace as the first container. In either
|
becomes fullscreen on the same workspace as the first container. In either
|
||||||
of those cases, the second container will gain focus.
|
of those cases, the second container will gain focus.
|
||||||
|
@ -356,12 +372,29 @@ set|plus|minus|toggle <amount>
|
||||||
*title_format* <format>
|
*title_format* <format>
|
||||||
Sets the format of window titles. The following placeholders may be used:
|
Sets the format of window titles. The following placeholders may be used:
|
||||||
|
|
||||||
%title - The title supplied by the window ++
|
*%title*
|
||||||
%app_id - The wayland app ID (applicable to wayland windows only) ++
|
The title supplied by the window
|
||||||
%class - The X11 classname (applicable to xwayland windows only) ++
|
|
||||||
%instance - The X11 instance (applicable to xwayland windows only) ++
|
*%app_id*
|
||||||
%shell - The protocol the window is using (typically xwayland or
|
The wayland app ID (applicable to wayland windows only)
|
||||||
xdg_shell)
|
|
||||||
|
*%class*
|
||||||
|
The X11 classname (applicable to xwayland windows only)
|
||||||
|
|
||||||
|
*%instance*
|
||||||
|
The X11 instance (applicable to xwayland windows only)
|
||||||
|
|
||||||
|
*%shell*
|
||||||
|
The protocol the window is using (typically xwayland or xdg_shell)
|
||||||
|
|
||||||
|
*%sandbox_engine*
|
||||||
|
The associated sandbox engine
|
||||||
|
|
||||||
|
*%sandbox_app_id*
|
||||||
|
The app ID provided by the associated sandbox engine
|
||||||
|
|
||||||
|
*%sandbox_instance_id*
|
||||||
|
The instance ID provided by the associated sandbox engine
|
||||||
|
|
||||||
This command is typically used with *for_window* criteria. For example:
|
This command is typically used with *for_window* criteria. For example:
|
||||||
|
|
||||||
|
@ -371,18 +404,19 @@ set|plus|minus|toggle <amount>
|
||||||
|
|
||||||
The default format is "%title".
|
The default format is "%title".
|
||||||
|
|
||||||
|
## Config or runtime commands
|
||||||
The following commands may be used either in the configuration file or at
|
The following commands may be used either in the configuration file or at
|
||||||
runtime.
|
runtime.
|
||||||
|
|
||||||
*assign* <criteria> [→] [workspace] [number] <workspace>
|
*assign* <criteria> [→] [workspace] [number] <workspace>
|
||||||
Assigns views matching _criteria_ (see *CRITERIA* for details) to
|
Assigns windows matching _criteria_ (see *CRITERIA* for details) to
|
||||||
_workspace_. The → (U+2192) is optional and cosmetic. This command is
|
_workspace_. The → (U+2192) is optional and cosmetic. This command is
|
||||||
equivalent to:
|
equivalent to:
|
||||||
|
|
||||||
for_window <criteria> move container to workspace <workspace>
|
for_window <criteria> move container to workspace <workspace>
|
||||||
|
|
||||||
*assign* <criteria> [→] output left|right|up|down|<name>
|
*assign* <criteria> [→] output left|right|up|down|<name>
|
||||||
Assigns views matching _criteria_ (see *CRITERIA* for details) to the
|
Assigns windows matching _criteria_ (see *CRITERIA* for details) to the
|
||||||
specified output. The → (U+2192) is optional and cosmetic. This command is
|
specified output. The → (U+2192) is optional and cosmetic. This command is
|
||||||
equivalent to:
|
equivalent to:
|
||||||
|
|
||||||
|
@ -565,10 +599,10 @@ runtime.
|
||||||
The window that has focus.
|
The window that has focus.
|
||||||
|
|
||||||
*client.focused_inactive*
|
*client.focused_inactive*
|
||||||
The most recently focused view within a container which is not focused.
|
The most recently focused window within a container which is not focused.
|
||||||
|
|
||||||
*client.focused_tab_title*
|
*client.focused_tab_title*
|
||||||
A view that has focused descendant container.
|
A window that has focused descendant container.
|
||||||
Tab or stack container title that is the parent of the focused 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
|
but is not directly focused. Defaults to focused_inactive if not
|
||||||
specified and does not use the indicator and child_border colors.
|
specified and does not use the indicator and child_border colors.
|
||||||
|
@ -577,10 +611,10 @@ runtime.
|
||||||
Ignored (present for i3 compatibility).
|
Ignored (present for i3 compatibility).
|
||||||
|
|
||||||
*client.unfocused*
|
*client.unfocused*
|
||||||
A view that does not have focus.
|
A window that does not have focus.
|
||||||
|
|
||||||
*client.urgent*
|
*client.urgent*
|
||||||
A view with an urgency hint. *Note*: Native Wayland windows do not
|
A window with an urgency hint. *Note*: Native Wayland windows do not
|
||||||
support urgency. Urgency only works for Xwayland windows.
|
support urgency. Urgency only works for Xwayland windows.
|
||||||
|
|
||||||
The meaning of each color is:
|
The meaning of each color is:
|
||||||
|
@ -595,12 +629,12 @@ runtime.
|
||||||
The text color of the title bar.
|
The text color of the title bar.
|
||||||
|
|
||||||
_indicator_
|
_indicator_
|
||||||
The color used to indicate where a new view will open. In a tiled
|
The color used to indicate where a new window will open. In a tiled
|
||||||
container, this would paint the right border of the current view if a
|
container, this would paint the right border of the current window if a
|
||||||
new view would be opened to the right.
|
new window would be opened to the right.
|
||||||
|
|
||||||
_child_border_
|
_child_border_
|
||||||
The border around the view itself.
|
The border around the window itself.
|
||||||
|
|
||||||
The default colors are:
|
The default colors are:
|
||||||
|
|
||||||
|
@ -738,7 +772,7 @@ The default colors are:
|
||||||
|
|
||||||
*gaps* inner|outer|horizontal|vertical|top|right|bottom|left <amount>
|
*gaps* inner|outer|horizontal|vertical|top|right|bottom|left <amount>
|
||||||
Sets default _amount_ pixels of _inner_ or _outer_ gap, where the inner
|
Sets default _amount_ pixels of _inner_ or _outer_ gap, where the inner
|
||||||
affects spacing around each view and outer affects the spacing around each
|
affects spacing around each window and outer affects the spacing around each
|
||||||
workspace. Outer gaps are in addition to inner gaps. To reduce or remove
|
workspace. Outer gaps are in addition to inner gaps. To reduce or remove
|
||||||
outer gaps, outer gaps can be set to a negative value. _outer_ gaps can
|
outer gaps, outer gaps can be set to a negative value. _outer_ gaps can
|
||||||
also be specified per side with _top_, _right_, _bottom_, and _left_ or
|
also be specified per side with _top_, _right_, _bottom_, and _left_ or
|
||||||
|
@ -810,9 +844,9 @@ The default colors are:
|
||||||
A list of output names may be obtained via *swaymsg -t get_outputs*.
|
A list of output names may be obtained via *swaymsg -t get_outputs*.
|
||||||
|
|
||||||
*popup_during_fullscreen* smart|ignore|leave_fullscreen
|
*popup_during_fullscreen* smart|ignore|leave_fullscreen
|
||||||
Determines what to do when a fullscreen view opens a dialog.
|
Determines what to do when a fullscreen window opens a dialog.
|
||||||
If _smart_ (the default), the dialog will be displayed. If _ignore_, the
|
If _smart_ (the default), the dialog will be displayed. If _ignore_, the
|
||||||
dialog will not be rendered. If _leave_fullscreen_, the view will exit
|
dialog will not be rendered. If _leave_fullscreen_, the window will exit
|
||||||
fullscreen mode and the dialog will be rendered.
|
fullscreen mode and the dialog will be rendered.
|
||||||
|
|
||||||
*primary_selection* enabled|disabled
|
*primary_selection* enabled|disabled
|
||||||
|
@ -938,18 +972,18 @@ The default colors are:
|
||||||
A criteria is a string in the form of, for example:
|
A criteria is a string in the form of, for example:
|
||||||
|
|
||||||
```
|
```
|
||||||
[class="[Rr]egex.*" title="some title"]
|
[app_id="some-application" title="[Rr]egex.*"]
|
||||||
```
|
```
|
||||||
|
|
||||||
The string contains one or more (space separated) attribute/value pairs. They
|
The string contains one or more (space separated) attribute/value pairs. They
|
||||||
are used by some commands to choose which views to execute actions on. All
|
are used by some commands to choose which windows to execute actions on. All
|
||||||
attributes must match for the criteria to match. Criteria is retained across
|
attributes must match for the criteria to match. Criteria is retained across
|
||||||
commands separated by a *,*, but will be reset (and allow for new criteria, if
|
commands separated by a *,*, but will be reset (and allow for new criteria, if
|
||||||
desired) for commands separated by a *;*.
|
desired) for commands separated by a *;*.
|
||||||
|
|
||||||
Criteria may be used with either the *for_window* or *assign* commands to
|
Criteria may be used with either the *for_window* or *assign* commands to
|
||||||
specify operations to perform on new views. A criteria may also be used to
|
specify operations to perform on new windows. A criteria may also be used to
|
||||||
perform specific commands (ones that normally act upon one window) on all views
|
perform specific commands (ones that normally act upon one window) on all windows
|
||||||
that match that criteria. For example:
|
that match that criteria. For example:
|
||||||
|
|
||||||
Focus on a window with the mark "IRC":
|
Focus on a window with the mark "IRC":
|
||||||
|
@ -958,10 +992,19 @@ Focus on a window with the mark "IRC":
|
||||||
[con_mark="IRC"] focus
|
[con_mark="IRC"] focus
|
||||||
```
|
```
|
||||||
|
|
||||||
Kill all windows with the title "Emacs":
|
Kill all windows where the title contains "Emacs":
|
||||||
|
|
||||||
```
|
```
|
||||||
[class="Emacs"] kill
|
[title="Emacs"] kill
|
||||||
|
```
|
||||||
|
|
||||||
|
Several attributes allow regular expressions. These use Perl-compatible regular
|
||||||
|
expressions (PCRE2), which are documented in *pcre2pattern*(3) and summarized in
|
||||||
|
*pcre2syntax*(3). For example, this moves all windows with titles ending in
|
||||||
|
"sway" or "Sway" to workspace 1:
|
||||||
|
|
||||||
|
```
|
||||||
|
[title="[Ss]way$"] move workspace 1
|
||||||
```
|
```
|
||||||
|
|
||||||
You may like to use swaymsg -t get_tree for finding the values of these
|
You may like to use swaymsg -t get_tree for finding the values of these
|
||||||
|
@ -1037,10 +1080,27 @@ The following attributes may be matched with:
|
||||||
applications and requires XWayland.
|
applications and requires XWayland.
|
||||||
|
|
||||||
*workspace*
|
*workspace*
|
||||||
Compare against the workspace name for this view. Can be a regular
|
Compare against the workspace name for this window. Can be a regular
|
||||||
expression. If the value is \_\_focused\_\_, then all the views on the
|
expression. If the value is \_\_focused\_\_, then all the windows on the
|
||||||
currently focused workspace matches.
|
currently focused workspace matches.
|
||||||
|
|
||||||
|
*sandbox_engine*
|
||||||
|
Compare against the associated sandbox engine. Can be a regular expression.
|
||||||
|
If the value is \_\_focused\_\_, then the sandbox engine must be the same as
|
||||||
|
that of the currently focused window.
|
||||||
|
|
||||||
|
*sandbox_app_id*
|
||||||
|
Compare against the app ID provided by the associated sandbox engine. Can be
|
||||||
|
a regular expression. If the value is \_\_focused\_\_, then the sandbox app
|
||||||
|
ID must be the same as that of the currently focused window.
|
||||||
|
|
||||||
|
*sandbox_instance_id*
|
||||||
|
Compare against the instance ID provided by the associated sandbox engine.
|
||||||
|
Can be a regular expression. If the value is \_\_focused\_\_, then the
|
||||||
|
sandbox instance ID must be the same as that of the currently focused
|
||||||
|
window.
|
||||||
|
|
||||||
# SEE ALSO
|
# SEE ALSO
|
||||||
|
|
||||||
*sway*(1) *sway-input*(5) *sway-output*(5) *sway-bar*(5) *sway-ipc*(7)
|
*sway*(1) *sway-input*(5) *sway-output*(5) *sway-bar*(5) *sway-ipc*(7)
|
||||||
|
*pcre2pattern*(3) *pcre2syntax*(3)
|
||||||
|
|
|
@ -64,18 +64,6 @@ static int get_text_width(struct sway_text_node *props) {
|
||||||
return MAX(width, 0);
|
return MAX(width, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void update_source_box(struct text_buffer *buffer) {
|
|
||||||
struct sway_text_node *props = &buffer->props;
|
|
||||||
struct wlr_fbox source_box = {
|
|
||||||
.x = 0,
|
|
||||||
.y = 0,
|
|
||||||
.width = ceil(get_text_width(props) * buffer->scale),
|
|
||||||
.height = ceil(props->height * buffer->scale),
|
|
||||||
};
|
|
||||||
|
|
||||||
wlr_scene_buffer_set_source_box(buffer->buffer_node, &source_box);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void render_backing_buffer(struct text_buffer *buffer) {
|
static void render_backing_buffer(struct text_buffer *buffer) {
|
||||||
if (!buffer->visible) {
|
if (!buffer->visible) {
|
||||||
return;
|
return;
|
||||||
|
@ -87,7 +75,7 @@ static void render_backing_buffer(struct text_buffer *buffer) {
|
||||||
}
|
}
|
||||||
|
|
||||||
float scale = buffer->scale;
|
float scale = buffer->scale;
|
||||||
int width = ceil(buffer->props.width * scale);
|
int width = ceil(get_text_width(&buffer->props) * scale);
|
||||||
int height = ceil(buffer->props.height * scale);
|
int height = ceil(buffer->props.height * scale);
|
||||||
float *color = (float *)&buffer->props.color;
|
float *color = (float *)&buffer->props.color;
|
||||||
float *background = (float *)&buffer->props.background;
|
float *background = (float *)&buffer->props.background;
|
||||||
|
@ -147,13 +135,12 @@ static void render_backing_buffer(struct text_buffer *buffer) {
|
||||||
|
|
||||||
wlr_scene_buffer_set_buffer(buffer->buffer_node, &cairo_buffer->base);
|
wlr_scene_buffer_set_buffer(buffer->buffer_node, &cairo_buffer->base);
|
||||||
wlr_buffer_drop(&cairo_buffer->base);
|
wlr_buffer_drop(&cairo_buffer->base);
|
||||||
update_source_box(buffer);
|
|
||||||
|
|
||||||
pixman_region32_t opaque;
|
pixman_region32_t opaque;
|
||||||
pixman_region32_init(&opaque);
|
pixman_region32_init(&opaque);
|
||||||
if (background[3] == 1) {
|
if (background[3] == 1) {
|
||||||
pixman_region32_union_rect(&opaque, &opaque, 0, 0,
|
pixman_region32_union_rect(&opaque, &opaque, 0, 0,
|
||||||
buffer->props.width, buffer->props.height);
|
get_text_width(&buffer->props), buffer->props.height);
|
||||||
}
|
}
|
||||||
wlr_scene_buffer_set_opaque_region(buffer->buffer_node, &opaque);
|
wlr_scene_buffer_set_opaque_region(buffer->buffer_node, &opaque);
|
||||||
pixman_region32_fini(&opaque);
|
pixman_region32_fini(&opaque);
|
||||||
|
@ -300,7 +287,6 @@ void sway_text_node_set_max_width(struct sway_text_node *node, int max_width) {
|
||||||
buffer->props.max_width = max_width;
|
buffer->props.max_width = max_width;
|
||||||
wlr_scene_buffer_set_dest_size(buffer->buffer_node,
|
wlr_scene_buffer_set_dest_size(buffer->buffer_node,
|
||||||
get_text_width(&buffer->props), buffer->props.height);
|
get_text_width(&buffer->props), buffer->props.height);
|
||||||
update_source_box(buffer);
|
|
||||||
render_backing_buffer(buffer);
|
render_backing_buffer(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,35 +64,27 @@ bool swaynag_spawn(const char *swaynag_command,
|
||||||
goto failed;
|
goto failed;
|
||||||
} else if (pid == 0) {
|
} else if (pid == 0) {
|
||||||
restore_nofile_limit();
|
restore_nofile_limit();
|
||||||
|
if (!sway_set_cloexec(sockets[1], false)) {
|
||||||
pid = fork();
|
|
||||||
if (pid < 0) {
|
|
||||||
sway_log_errno(SWAY_ERROR, "fork failed");
|
|
||||||
_exit(EXIT_FAILURE);
|
|
||||||
} else if (pid == 0) {
|
|
||||||
if (!sway_set_cloexec(sockets[1], false)) {
|
|
||||||
_exit(EXIT_FAILURE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (swaynag->detailed) {
|
|
||||||
close(swaynag->fd[1]);
|
|
||||||
dup2(swaynag->fd[0], STDIN_FILENO);
|
|
||||||
close(swaynag->fd[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
char wayland_socket_str[16];
|
|
||||||
snprintf(wayland_socket_str, sizeof(wayland_socket_str),
|
|
||||||
"%d", sockets[1]);
|
|
||||||
setenv("WAYLAND_SOCKET", wayland_socket_str, true);
|
|
||||||
|
|
||||||
size_t length = strlen(swaynag_command) + strlen(swaynag->args) + 2;
|
|
||||||
char *cmd = malloc(length);
|
|
||||||
snprintf(cmd, length, "%s %s", swaynag_command, swaynag->args);
|
|
||||||
execlp("sh", "sh", "-c", cmd, NULL);
|
|
||||||
sway_log_errno(SWAY_ERROR, "execlp failed");
|
|
||||||
_exit(EXIT_FAILURE);
|
_exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
_exit(EXIT_SUCCESS);
|
|
||||||
|
if (swaynag->detailed) {
|
||||||
|
close(swaynag->fd[1]);
|
||||||
|
dup2(swaynag->fd[0], STDIN_FILENO);
|
||||||
|
close(swaynag->fd[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
char wayland_socket_str[16];
|
||||||
|
snprintf(wayland_socket_str, sizeof(wayland_socket_str),
|
||||||
|
"%d", sockets[1]);
|
||||||
|
setenv("WAYLAND_SOCKET", wayland_socket_str, true);
|
||||||
|
|
||||||
|
size_t length = strlen(swaynag_command) + strlen(swaynag->args) + 2;
|
||||||
|
char *cmd = malloc(length);
|
||||||
|
snprintf(cmd, length, "%s %s", swaynag_command, swaynag->args);
|
||||||
|
execlp("sh", "sh", "-c", cmd, NULL);
|
||||||
|
sway_log_errno(SWAY_ERROR, "execlp failed");
|
||||||
|
_exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (swaynag->detailed) {
|
if (swaynag->detailed) {
|
||||||
|
@ -107,11 +99,6 @@ bool swaynag_spawn(const char *swaynag_command,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (waitpid(pid, NULL, 0) < 0) {
|
|
||||||
sway_log_errno(SWAY_ERROR, "waitpid failed");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
failed:
|
failed:
|
||||||
|
|
|
@ -29,7 +29,7 @@ static void apply_horiz_layout(list_t *children, struct wlr_box *parent) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate each height fraction
|
// Calculate each width fraction
|
||||||
double total_width_fraction = 0;
|
double total_width_fraction = 0;
|
||||||
for (int i = 0; i < children->length; ++i) {
|
for (int i = 0; i < children->length; ++i) {
|
||||||
struct sway_container *child = children->items[i];
|
struct sway_container *child = children->items[i];
|
||||||
|
@ -82,12 +82,18 @@ static void apply_horiz_layout(list_t *children, struct wlr_box *parent) {
|
||||||
child->pending.y = parent->y;
|
child->pending.y = parent->y;
|
||||||
child->pending.width = round(child->width_fraction * child_total_width);
|
child->pending.width = round(child->width_fraction * child_total_width);
|
||||||
child->pending.height = parent->height;
|
child->pending.height = parent->height;
|
||||||
child_x += child->pending.width + inner_gap;
|
|
||||||
|
|
||||||
// Make last child use remaining width of parent
|
// Make last child use remaining width of parent
|
||||||
if (i == children->length - 1) {
|
if (i == children->length - 1) {
|
||||||
child->pending.width = parent->x + parent->width - child->pending.x;
|
child->pending.width = parent->x + parent->width - child->pending.x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Arbitrary lower bound for window size
|
||||||
|
if (child->pending.width < 10 || child->pending.height < 10) {
|
||||||
|
child->pending.width = 0;
|
||||||
|
child->pending.height = 0;
|
||||||
|
}
|
||||||
|
child_x += child->pending.width + inner_gap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,12 +167,18 @@ static void apply_vert_layout(list_t *children, struct wlr_box *parent) {
|
||||||
child->pending.y = child_y;
|
child->pending.y = child_y;
|
||||||
child->pending.width = parent->width;
|
child->pending.width = parent->width;
|
||||||
child->pending.height = round(child->height_fraction * child_total_height);
|
child->pending.height = round(child->height_fraction * child_total_height);
|
||||||
child_y += child->pending.height + inner_gap;
|
|
||||||
|
|
||||||
// Make last child use remaining height of parent
|
// Make last child use remaining height of parent
|
||||||
if (i == children->length - 1) {
|
if (i == children->length - 1) {
|
||||||
child->pending.height = parent->y + parent->height - child->pending.y;
|
child->pending.height = parent->y + parent->height - child->pending.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Arbitrary lower bound for window size
|
||||||
|
if (child->pending.width < 10 || child->pending.height < 10) {
|
||||||
|
child->pending.width = 0;
|
||||||
|
child->pending.height = 0;
|
||||||
|
}
|
||||||
|
child_y += child->pending.height + inner_gap;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,14 +326,9 @@ void arrange_output(struct sway_output *output) {
|
||||||
if (config->reloading) {
|
if (config->reloading) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
struct wlr_box output_box;
|
if (!output->wlr_output->enabled) {
|
||||||
wlr_output_layout_get_box(root->output_layout,
|
return;
|
||||||
output->wlr_output, &output_box);
|
}
|
||||||
output->lx = output_box.x;
|
|
||||||
output->ly = output_box.y;
|
|
||||||
output->width = output_box.width;
|
|
||||||
output->height = output_box.height;
|
|
||||||
|
|
||||||
for (int i = 0; i < output->workspaces->length; ++i) {
|
for (int i = 0; i < output->workspaces->length; ++i) {
|
||||||
struct sway_workspace *workspace = output->workspaces->items[i];
|
struct sway_workspace *workspace = output->workspaces->items[i];
|
||||||
arrange_workspace(workspace);
|
arrange_workspace(workspace);
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "sway/tree/workspace.h"
|
#include "sway/tree/workspace.h"
|
||||||
#include "sway/xdg_decoration.h"
|
#include "sway/xdg_decoration.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
|
#include "pango.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "stringop.h"
|
#include "stringop.h"
|
||||||
|
|
||||||
|
@ -348,7 +349,7 @@ void container_arrange_title_bar(struct sway_container *con) {
|
||||||
h_padding = width - config->titlebar_h_padding - marks_buffer_width;
|
h_padding = width - config->titlebar_h_padding - marks_buffer_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
h_padding = MAX(h_padding, 0);
|
h_padding = MAX(h_padding, config->titlebar_h_padding);
|
||||||
|
|
||||||
int alloc_width = MIN((int)node->width,
|
int alloc_width = MIN((int)node->width,
|
||||||
width - h_padding - config->titlebar_h_padding);
|
width - h_padding - config->titlebar_h_padding);
|
||||||
|
@ -374,7 +375,7 @@ void container_arrange_title_bar(struct sway_container *con) {
|
||||||
h_padding = config->titlebar_h_padding;
|
h_padding = config->titlebar_h_padding;
|
||||||
}
|
}
|
||||||
|
|
||||||
h_padding = MAX(h_padding, 0);
|
h_padding = MAX(h_padding, config->titlebar_h_padding);
|
||||||
|
|
||||||
int alloc_width = MIN((int) node->width,
|
int alloc_width = MIN((int) node->width,
|
||||||
width - h_padding - config->titlebar_h_padding);
|
width - h_padding - config->titlebar_h_padding);
|
||||||
|
@ -499,6 +500,7 @@ void container_destroy(struct sway_container *con) {
|
||||||
}
|
}
|
||||||
free(con->title);
|
free(con->title);
|
||||||
free(con->formatted_title);
|
free(con->formatted_title);
|
||||||
|
free(con->title_format);
|
||||||
list_free(con->pending.children);
|
list_free(con->pending.children);
|
||||||
list_free(con->current.children);
|
list_free(con->current.children);
|
||||||
|
|
||||||
|
@ -506,6 +508,8 @@ void container_destroy(struct sway_container *con) {
|
||||||
|
|
||||||
if (con->view && con->view->container == con) {
|
if (con->view && con->view->container == con) {
|
||||||
con->view->container = NULL;
|
con->view->container = NULL;
|
||||||
|
wl_list_remove(&con->output_enter.link);
|
||||||
|
wl_list_remove(&con->output_leave.link);
|
||||||
wlr_scene_node_destroy(&con->output_handler->node);
|
wlr_scene_node_destroy(&con->output_handler->node);
|
||||||
if (con->view->destroying) {
|
if (con->view->destroying) {
|
||||||
view_destroy(con->view);
|
view_destroy(con->view);
|
||||||
|
@ -645,6 +649,100 @@ bool container_has_ancestor(struct sway_container *descendant,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char *escape_pango_markup(const char *buffer) {
|
||||||
|
size_t length = escape_markup_text(buffer, NULL);
|
||||||
|
char *escaped_title = calloc(length + 1, sizeof(char));
|
||||||
|
escape_markup_text(buffer, escaped_title);
|
||||||
|
return escaped_title;
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_t append_prop(char *buffer, const char *value) {
|
||||||
|
if (!value) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
// If using pango_markup in font, we need to escape all markup chars
|
||||||
|
// from values to make sure tags are not inserted by clients
|
||||||
|
if (config->pango_markup) {
|
||||||
|
char *escaped_value = escape_pango_markup(value);
|
||||||
|
lenient_strcat(buffer, escaped_value);
|
||||||
|
size_t len = strlen(escaped_value);
|
||||||
|
free(escaped_value);
|
||||||
|
return len;
|
||||||
|
} else {
|
||||||
|
lenient_strcat(buffer, value);
|
||||||
|
return strlen(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate and return the length of the formatted title.
|
||||||
|
* If buffer is not NULL, also populate the buffer with the formatted title.
|
||||||
|
*/
|
||||||
|
size_t parse_title_format(struct sway_container *container, char *buffer) {
|
||||||
|
if (!container->title_format || strcmp(container->title_format, "%title") == 0) {
|
||||||
|
if (container->view) {
|
||||||
|
return append_prop(buffer, view_get_title(container->view));
|
||||||
|
} else {
|
||||||
|
return container_build_representation(container->pending.layout, container->pending.children, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len = 0;
|
||||||
|
char *format = container->title_format;
|
||||||
|
char *next = strchr(format, '%');
|
||||||
|
while (next) {
|
||||||
|
// Copy everything up to the %
|
||||||
|
lenient_strncat(buffer, format, next - format);
|
||||||
|
len += next - format;
|
||||||
|
format = next;
|
||||||
|
|
||||||
|
if (has_prefix(next, "%title")) {
|
||||||
|
if (container->view) {
|
||||||
|
len += append_prop(buffer, view_get_title(container->view));
|
||||||
|
} else {
|
||||||
|
len += container_build_representation(container->pending.layout, container->pending.children, buffer);
|
||||||
|
}
|
||||||
|
format += strlen("%title");
|
||||||
|
} else if (container->view) {
|
||||||
|
if (has_prefix(next, "%app_id")) {
|
||||||
|
len += append_prop(buffer, view_get_app_id(container->view));
|
||||||
|
format += strlen("%app_id");
|
||||||
|
} else if (has_prefix(next, "%class")) {
|
||||||
|
len += append_prop(buffer, view_get_class(container->view));
|
||||||
|
format += strlen("%class");
|
||||||
|
} else if (has_prefix(next, "%instance")) {
|
||||||
|
len += append_prop(buffer, view_get_instance(container->view));
|
||||||
|
format += strlen("%instance");
|
||||||
|
} else if (has_prefix(next, "%shell")) {
|
||||||
|
len += append_prop(buffer, view_get_shell(container->view));
|
||||||
|
format += strlen("%shell");
|
||||||
|
} else if (has_prefix(next, "%sandbox_engine")) {
|
||||||
|
len += append_prop(buffer, view_get_sandbox_engine(container->view));
|
||||||
|
format += strlen("%sandbox_engine");
|
||||||
|
} else if (has_prefix(next, "%sandbox_app_id")) {
|
||||||
|
len += append_prop(buffer, view_get_sandbox_app_id(container->view));
|
||||||
|
format += strlen("%sandbox_app_id");
|
||||||
|
} else if (has_prefix(next, "%sandbox_instance_id")) {
|
||||||
|
len += append_prop(buffer, view_get_sandbox_instance_id(container->view));
|
||||||
|
format += strlen("%sandbox_instance_id");
|
||||||
|
} else {
|
||||||
|
lenient_strcat(buffer, "%");
|
||||||
|
++format;
|
||||||
|
++len;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
lenient_strcat(buffer, "%");
|
||||||
|
++format;
|
||||||
|
++len;
|
||||||
|
}
|
||||||
|
next = strchr(format, '%');
|
||||||
|
}
|
||||||
|
lenient_strcat(buffer, format);
|
||||||
|
len += strlen(format);
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate and return the length of the tree representation.
|
* Calculate and return the length of the tree representation.
|
||||||
* An example tree representation is: V[Terminal, Firefox]
|
* An example tree representation is: V[Terminal, Firefox]
|
||||||
|
@ -689,7 +787,7 @@ size_t container_build_representation(enum sway_container_layout layout,
|
||||||
len += strlen(identifier);
|
len += strlen(identifier);
|
||||||
lenient_strcat(buffer, identifier);
|
lenient_strcat(buffer, identifier);
|
||||||
} else {
|
} else {
|
||||||
len += 6;
|
len += strlen("(null)");
|
||||||
lenient_strcat(buffer, "(null)");
|
lenient_strcat(buffer, "(null)");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -700,16 +798,14 @@ size_t container_build_representation(enum sway_container_layout layout,
|
||||||
|
|
||||||
void container_update_representation(struct sway_container *con) {
|
void container_update_representation(struct sway_container *con) {
|
||||||
if (!con->view) {
|
if (!con->view) {
|
||||||
size_t len = container_build_representation(con->pending.layout,
|
size_t len = parse_title_format(con, NULL);
|
||||||
con->pending.children, NULL);
|
|
||||||
free(con->formatted_title);
|
free(con->formatted_title);
|
||||||
con->formatted_title = calloc(len + 1, sizeof(char));
|
con->formatted_title = calloc(len + 1, sizeof(char));
|
||||||
if (!sway_assert(con->formatted_title,
|
if (!sway_assert(con->formatted_title,
|
||||||
"Unable to allocate title string")) {
|
"Unable to allocate title string")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
container_build_representation(con->pending.layout, con->pending.children,
|
parse_title_format(con, con->formatted_title);
|
||||||
con->formatted_title);
|
|
||||||
|
|
||||||
if (con->title_bar.title_text) {
|
if (con->title_bar.title_text) {
|
||||||
sway_text_node_set_text(con->title_bar.title_text, con->formatted_title);
|
sway_text_node_set_text(con->title_bar.title_text, con->formatted_title);
|
||||||
|
@ -773,11 +869,11 @@ void floating_fix_coordinates(struct sway_container *con, struct wlr_box *old, s
|
||||||
// Fall back to centering on the workspace.
|
// Fall back to centering on the workspace.
|
||||||
container_floating_move_to_center(con);
|
container_floating_move_to_center(con);
|
||||||
} else {
|
} else {
|
||||||
int rel_x = con->pending.x - old->x + (con->pending.width / 2);
|
double rel_x = con->pending.x - old->x + (con->pending.width / 2);
|
||||||
int rel_y = con->pending.y - old->y + (con->pending.height / 2);
|
double rel_y = con->pending.y - old->y + (con->pending.height / 2);
|
||||||
|
|
||||||
con->pending.x = new->x + (double)(rel_x * new->width) / old->width - (con->pending.width / 2);
|
con->pending.x = new->x + (rel_x * new->width) / old->width - (con->pending.width / 2);
|
||||||
con->pending.y = new->y + (double)(rel_y * new->height) / old->height - (con->pending.height / 2);
|
con->pending.y = new->y + (rel_y * new->height) / old->height - (con->pending.height / 2);
|
||||||
|
|
||||||
sway_log(SWAY_DEBUG, "Transformed container %p to coords (%f, %f)", con, con->pending.x, con->pending.y);
|
sway_log(SWAY_DEBUG, "Transformed container %p to coords (%f, %f)", con, con->pending.x, con->pending.y);
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,12 +180,7 @@ void output_enable(struct sway_output *output) {
|
||||||
ws->layout = output_get_default_layout(output);
|
ws->layout = output_get_default_layout(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
input_manager_configure_xcursor();
|
|
||||||
|
|
||||||
wl_signal_emit_mutable(&root->events.new_node, &output->node);
|
wl_signal_emit_mutable(&root->events.new_node, &output->node);
|
||||||
|
|
||||||
arrange_layers(output);
|
|
||||||
arrange_root();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void evacuate_sticky(struct sway_workspace *old_ws,
|
static void evacuate_sticky(struct sway_workspace *old_ws,
|
||||||
|
@ -278,7 +273,6 @@ void output_destroy(struct sway_output *output) {
|
||||||
destroy_scene_layers(output);
|
destroy_scene_layers(output);
|
||||||
list_free(output->workspaces);
|
list_free(output->workspaces);
|
||||||
list_free(output->current.workspaces);
|
list_free(output->current.workspaces);
|
||||||
wl_event_source_remove(output->repaint_timer);
|
|
||||||
wlr_color_transform_unref(output->color_transform);
|
wlr_color_transform_unref(output->color_transform);
|
||||||
free(output);
|
free(output);
|
||||||
}
|
}
|
||||||
|
@ -300,13 +294,6 @@ void output_disable(struct sway_output *output) {
|
||||||
list_del(root->outputs, index);
|
list_del(root->outputs, index);
|
||||||
|
|
||||||
output->enabled = false;
|
output->enabled = false;
|
||||||
|
|
||||||
arrange_root();
|
|
||||||
|
|
||||||
// Reconfigure all devices, since devices with map_to_output directives for
|
|
||||||
// an output that goes offline should stop sending events as long as the
|
|
||||||
// output remains offline.
|
|
||||||
input_manager_configure_all_input_mappings();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void output_begin_destroy(struct sway_output *output) {
|
void output_begin_destroy(struct sway_output *output) {
|
||||||
|
|
|
@ -19,12 +19,6 @@
|
||||||
|
|
||||||
struct sway_root *root;
|
struct sway_root *root;
|
||||||
|
|
||||||
static void output_layout_handle_change(struct wl_listener *listener,
|
|
||||||
void *data) {
|
|
||||||
arrange_root();
|
|
||||||
transaction_commit_dirty();
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sway_root *root_create(struct wl_display *wl_display) {
|
struct sway_root *root_create(struct wl_display *wl_display) {
|
||||||
struct sway_root *root = calloc(1, sizeof(struct sway_root));
|
struct sway_root *root = calloc(1, sizeof(struct sway_root));
|
||||||
if (!root) {
|
if (!root) {
|
||||||
|
@ -81,14 +75,10 @@ struct sway_root *root_create(struct wl_display *wl_display) {
|
||||||
root->non_desktop_outputs = create_list();
|
root->non_desktop_outputs = create_list();
|
||||||
root->scratchpad = create_list();
|
root->scratchpad = create_list();
|
||||||
|
|
||||||
root->output_layout_change.notify = output_layout_handle_change;
|
|
||||||
wl_signal_add(&root->output_layout->events.change,
|
|
||||||
&root->output_layout_change);
|
|
||||||
return root;
|
return root;
|
||||||
}
|
}
|
||||||
|
|
||||||
void root_destroy(struct sway_root *root) {
|
void root_destroy(struct sway_root *root) {
|
||||||
wl_list_remove(&root->output_layout_change.link);
|
|
||||||
list_free(root->scratchpad);
|
list_free(root->scratchpad);
|
||||||
list_free(root->non_desktop_outputs);
|
list_free(root->non_desktop_outputs);
|
||||||
list_free(root->outputs);
|
list_free(root->outputs);
|
||||||
|
|
127
sway/tree/view.c
127
sway/tree/view.c
|
@ -8,9 +8,11 @@
|
||||||
#include <wlr/types/wlr_foreign_toplevel_management_v1.h>
|
#include <wlr/types/wlr_foreign_toplevel_management_v1.h>
|
||||||
#include <wlr/types/wlr_fractional_scale_v1.h>
|
#include <wlr/types/wlr_fractional_scale_v1.h>
|
||||||
#include <wlr/types/wlr_output_layout.h>
|
#include <wlr/types/wlr_output_layout.h>
|
||||||
|
#include <wlr/types/wlr_security_context_v1.h>
|
||||||
#include <wlr/types/wlr_server_decoration.h>
|
#include <wlr/types/wlr_server_decoration.h>
|
||||||
#include <wlr/types/wlr_subcompositor.h>
|
#include <wlr/types/wlr_subcompositor.h>
|
||||||
#include <wlr/types/wlr_xdg_decoration_v1.h>
|
#include <wlr/types/wlr_xdg_decoration_v1.h>
|
||||||
|
#include <wlr/types/wlr_session_lock_v1.h>
|
||||||
#if WLR_HAS_XWAYLAND
|
#if WLR_HAS_XWAYLAND
|
||||||
#include <wlr/xwayland.h>
|
#include <wlr/xwayland.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -34,7 +36,6 @@
|
||||||
#include "sway/tree/workspace.h"
|
#include "sway/tree/workspace.h"
|
||||||
#include "sway/config.h"
|
#include "sway/config.h"
|
||||||
#include "sway/xdg_decoration.h"
|
#include "sway/xdg_decoration.h"
|
||||||
#include "pango.h"
|
|
||||||
#include "stringop.h"
|
#include "stringop.h"
|
||||||
|
|
||||||
bool view_init(struct sway_view *view, enum sway_view_type type,
|
bool view_init(struct sway_view *view, enum sway_view_type type,
|
||||||
|
@ -58,6 +59,7 @@ bool view_init(struct sway_view *view, enum sway_view_type type,
|
||||||
view->executed_criteria = create_list();
|
view->executed_criteria = create_list();
|
||||||
view->allow_request_urgent = true;
|
view->allow_request_urgent = true;
|
||||||
view->shortcuts_inhibit = SHORTCUTS_INHIBIT_DEFAULT;
|
view->shortcuts_inhibit = SHORTCUTS_INHIBIT_DEFAULT;
|
||||||
|
view->tearing_mode = TEARING_WINDOW_HINT;
|
||||||
wl_signal_init(&view->events.unmap);
|
wl_signal_init(&view->events.unmap);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -80,8 +82,6 @@ void view_destroy(struct sway_view *view) {
|
||||||
|
|
||||||
view_assign_ctx(view, NULL);
|
view_assign_ctx(view, NULL);
|
||||||
wlr_scene_node_destroy(&view->scene_tree->node);
|
wlr_scene_node_destroy(&view->scene_tree->node);
|
||||||
free(view->title_format);
|
|
||||||
|
|
||||||
if (view->impl->destroy) {
|
if (view->impl->destroy) {
|
||||||
view->impl->destroy(view);
|
view->impl->destroy(view);
|
||||||
} else {
|
} else {
|
||||||
|
@ -156,6 +156,34 @@ uint32_t view_get_window_type(struct sway_view *view) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct wlr_security_context_v1_state *security_context_from_view(
|
||||||
|
struct sway_view *view) {
|
||||||
|
const struct wl_client *client =
|
||||||
|
wl_resource_get_client(view->surface->resource);
|
||||||
|
const struct wlr_security_context_v1_state *security_context =
|
||||||
|
wlr_security_context_manager_v1_lookup_client(
|
||||||
|
server.security_context_manager_v1, client);
|
||||||
|
return security_context;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *view_get_sandbox_engine(struct sway_view *view) {
|
||||||
|
const struct wlr_security_context_v1_state *security_context =
|
||||||
|
security_context_from_view(view);
|
||||||
|
return security_context ? security_context->sandbox_engine : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *view_get_sandbox_app_id(struct sway_view *view) {
|
||||||
|
const struct wlr_security_context_v1_state *security_context =
|
||||||
|
security_context_from_view(view);
|
||||||
|
return security_context ? security_context->app_id : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *view_get_sandbox_instance_id(struct sway_view *view) {
|
||||||
|
const struct wlr_security_context_v1_state *security_context =
|
||||||
|
security_context_from_view(view);
|
||||||
|
return security_context ? security_context->instance_id : NULL;
|
||||||
|
}
|
||||||
|
|
||||||
const char *view_get_shell(struct sway_view *view) {
|
const char *view_get_shell(struct sway_view *view) {
|
||||||
switch(view->type) {
|
switch(view->type) {
|
||||||
case SWAY_VIEW_XDG_SHELL:
|
case SWAY_VIEW_XDG_SHELL:
|
||||||
|
@ -850,7 +878,7 @@ void view_map(struct sway_view *view, struct wlr_surface *wlr_surface,
|
||||||
#if WLR_HAS_XWAYLAND
|
#if WLR_HAS_XWAYLAND
|
||||||
struct wlr_xwayland_surface *xsurface;
|
struct wlr_xwayland_surface *xsurface;
|
||||||
if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(wlr_surface))) {
|
if ((xsurface = wlr_xwayland_surface_try_from_wlr_surface(wlr_surface))) {
|
||||||
set_focus &= wlr_xwayland_icccm_input_model(xsurface) !=
|
set_focus &= wlr_xwayland_surface_icccm_input_model(xsurface) !=
|
||||||
WLR_ICCCM_INPUT_MODEL_NONE;
|
WLR_ICCCM_INPUT_MODEL_NONE;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -983,6 +1011,9 @@ struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) {
|
||||||
if (wlr_layer_surface_v1_try_from_wlr_surface(wlr_surface) != NULL) {
|
if (wlr_layer_surface_v1_try_from_wlr_surface(wlr_surface) != NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if (wlr_session_lock_surface_v1_try_from_wlr_surface(wlr_surface) != NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
const char *role = wlr_surface->role ? wlr_surface->role->name : NULL;
|
const char *role = wlr_surface->role ? wlr_surface->role->name : NULL;
|
||||||
sway_log(SWAY_DEBUG, "Surface of unknown type (role %s): %p",
|
sway_log(SWAY_DEBUG, "Surface of unknown type (role %s): %p",
|
||||||
|
@ -990,77 +1021,6 @@ struct sway_view *view_from_wlr_surface(struct wlr_surface *wlr_surface) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *escape_pango_markup(const char *buffer) {
|
|
||||||
size_t length = escape_markup_text(buffer, NULL);
|
|
||||||
char *escaped_title = calloc(length + 1, sizeof(char));
|
|
||||||
escape_markup_text(buffer, escaped_title);
|
|
||||||
return escaped_title;
|
|
||||||
}
|
|
||||||
|
|
||||||
static size_t append_prop(char *buffer, const char *value) {
|
|
||||||
if (!value) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
// If using pango_markup in font, we need to escape all markup chars
|
|
||||||
// from values to make sure tags are not inserted by clients
|
|
||||||
if (config->pango_markup) {
|
|
||||||
char *escaped_value = escape_pango_markup(value);
|
|
||||||
lenient_strcat(buffer, escaped_value);
|
|
||||||
size_t len = strlen(escaped_value);
|
|
||||||
free(escaped_value);
|
|
||||||
return len;
|
|
||||||
} else {
|
|
||||||
lenient_strcat(buffer, value);
|
|
||||||
return strlen(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculate and return the length of the formatted title.
|
|
||||||
* If buffer is not NULL, also populate the buffer with the formatted title.
|
|
||||||
*/
|
|
||||||
static size_t parse_title_format(struct sway_view *view, char *buffer) {
|
|
||||||
if (!view->title_format || strcmp(view->title_format, "%title") == 0) {
|
|
||||||
return append_prop(buffer, view_get_title(view));
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t len = 0;
|
|
||||||
char *format = view->title_format;
|
|
||||||
char *next = strchr(format, '%');
|
|
||||||
while (next) {
|
|
||||||
// Copy everything up to the %
|
|
||||||
lenient_strncat(buffer, format, next - format);
|
|
||||||
len += next - format;
|
|
||||||
format = next;
|
|
||||||
|
|
||||||
if (strncmp(next, "%title", 6) == 0) {
|
|
||||||
len += append_prop(buffer, view_get_title(view));
|
|
||||||
format += 6;
|
|
||||||
} else if (strncmp(next, "%app_id", 7) == 0) {
|
|
||||||
len += append_prop(buffer, view_get_app_id(view));
|
|
||||||
format += 7;
|
|
||||||
} else if (strncmp(next, "%class", 6) == 0) {
|
|
||||||
len += append_prop(buffer, view_get_class(view));
|
|
||||||
format += 6;
|
|
||||||
} else if (strncmp(next, "%instance", 9) == 0) {
|
|
||||||
len += append_prop(buffer, view_get_instance(view));
|
|
||||||
format += 9;
|
|
||||||
} else if (strncmp(next, "%shell", 6) == 0) {
|
|
||||||
len += append_prop(buffer, view_get_shell(view));
|
|
||||||
format += 6;
|
|
||||||
} else {
|
|
||||||
lenient_strcat(buffer, "%");
|
|
||||||
++format;
|
|
||||||
++len;
|
|
||||||
}
|
|
||||||
next = strchr(format, '%');
|
|
||||||
}
|
|
||||||
lenient_strcat(buffer, format);
|
|
||||||
len += strlen(format);
|
|
||||||
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
void view_update_app_id(struct sway_view *view) {
|
void view_update_app_id(struct sway_view *view) {
|
||||||
const char *app_id = view_get_app_id(view);
|
const char *app_id = view_get_app_id(view);
|
||||||
|
|
||||||
|
@ -1089,7 +1049,7 @@ void view_update_title(struct sway_view *view, bool force) {
|
||||||
free(view->container->title);
|
free(view->container->title);
|
||||||
free(view->container->formatted_title);
|
free(view->container->formatted_title);
|
||||||
|
|
||||||
size_t len = parse_title_format(view, NULL);
|
size_t len = parse_title_format(view->container, NULL);
|
||||||
|
|
||||||
if (len) {
|
if (len) {
|
||||||
char *buffer = calloc(len + 1, sizeof(char));
|
char *buffer = calloc(len + 1, sizeof(char));
|
||||||
|
@ -1097,7 +1057,7 @@ void view_update_title(struct sway_view *view, bool force) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_title_format(view, buffer);
|
parse_title_format(view->container, buffer);
|
||||||
view->container->formatted_title = buffer;
|
view->container->formatted_title = buffer;
|
||||||
} else {
|
} else {
|
||||||
view->container->formatted_title = NULL;
|
view->container->formatted_title = NULL;
|
||||||
|
@ -1260,6 +1220,19 @@ bool view_is_transient_for(struct sway_view *child,
|
||||||
child->impl->is_transient_for(child, ancestor);
|
child->impl->is_transient_for(child, ancestor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool view_can_tear(struct sway_view *view) {
|
||||||
|
switch (view->tearing_mode) {
|
||||||
|
case TEARING_OVERRIDE_FALSE:
|
||||||
|
return false;
|
||||||
|
case TEARING_OVERRIDE_TRUE:
|
||||||
|
return true;
|
||||||
|
case TEARING_WINDOW_HINT:
|
||||||
|
return view->tearing_hint ==
|
||||||
|
WP_TEARING_CONTROL_V1_PRESENTATION_HINT_ASYNC;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static void send_frame_done_iterator(struct wlr_scene_buffer *scene_buffer,
|
static void send_frame_done_iterator(struct wlr_scene_buffer *scene_buffer,
|
||||||
int x, int y, void *data) {
|
int x, int y, void *data) {
|
||||||
struct timespec *when = data;
|
struct timespec *when = data;
|
||||||
|
|
|
@ -246,7 +246,7 @@ static void workspace_name_from_binding(const struct sway_binding * binding,
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the command is workspace number <name>, isolate the name
|
// If the command is workspace number <name>, isolate the name
|
||||||
if (strncmp(_target, "number ", strlen("number ")) == 0) {
|
if (has_prefix(_target, "number ")) {
|
||||||
size_t length = strlen(_target) - strlen("number ") + 1;
|
size_t length = strlen(_target) - strlen("number ") + 1;
|
||||||
char *temp = malloc(length);
|
char *temp = malloc(length);
|
||||||
strncpy(temp, _target + strlen("number "), length - 1);
|
strncpy(temp, _target + strlen("number "), length - 1);
|
||||||
|
|
|
@ -508,7 +508,7 @@ void bar_run(struct swaybar *bar) {
|
||||||
}
|
}
|
||||||
#if HAVE_TRAY
|
#if HAVE_TRAY
|
||||||
if (bar->tray) {
|
if (bar->tray) {
|
||||||
loop_add_fd(bar->eventloop, bar->tray->fd, POLLIN, tray_in, bar->tray->bus);
|
loop_add_fd(bar->eventloop, bar->tray->fd, POLLIN, tray_in, bar);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
while (bar->running) {
|
while (bar->running) {
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "loop.h"
|
#include "loop.h"
|
||||||
|
#include "stringop.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
void ipc_send_workspace_command(struct swaybar *bar, const char *ws) {
|
void ipc_send_workspace_command(struct swaybar *bar, const char *ws) {
|
||||||
|
@ -45,8 +46,8 @@ void ipc_send_workspace_command(struct swaybar *bar, const char *ws) {
|
||||||
|
|
||||||
char *parse_font(const char *font) {
|
char *parse_font(const char *font) {
|
||||||
char *new_font = NULL;
|
char *new_font = NULL;
|
||||||
if (strncmp("pango:", font, 6) == 0) {
|
if (has_prefix(font, "pango:")) {
|
||||||
font += 6;
|
font += strlen("pango:");
|
||||||
}
|
}
|
||||||
new_font = strdup(font);
|
new_font = strdup(font);
|
||||||
return new_font;
|
return new_font;
|
||||||
|
@ -518,8 +519,7 @@ static bool handle_barconfig_update(struct swaybar *bar, const char *payload,
|
||||||
#if HAVE_TRAY
|
#if HAVE_TRAY
|
||||||
if (oldcfg->tray_hidden && !newcfg->tray_hidden) {
|
if (oldcfg->tray_hidden && !newcfg->tray_hidden) {
|
||||||
bar->tray = create_tray(bar);
|
bar->tray = create_tray(bar);
|
||||||
loop_add_fd(bar->eventloop, bar->tray->fd, POLLIN, tray_in,
|
loop_add_fd(bar->eventloop, bar->tray->fd, POLLIN, tray_in, bar);
|
||||||
bar->tray->bus);
|
|
||||||
} else if (bar->tray && newcfg->tray_hidden) {
|
} else if (bar->tray && newcfg->tray_hidden) {
|
||||||
loop_remove_fd(bar->eventloop, bar->tray->fd);
|
loop_remove_fd(bar->eventloop, bar->tray->fd);
|
||||||
destroy_tray(bar->tray);
|
destroy_tray(bar->tray);
|
||||||
|
|
|
@ -29,6 +29,7 @@ struct render_context {
|
||||||
cairo_font_options_t *textaa_sharp;
|
cairo_font_options_t *textaa_sharp;
|
||||||
cairo_font_options_t *textaa_safe;
|
cairo_font_options_t *textaa_safe;
|
||||||
uint32_t background_color;
|
uint32_t background_color;
|
||||||
|
bool has_transparency;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void choose_text_aa_mode(struct render_context *ctx, uint32_t fontcolor) {
|
static void choose_text_aa_mode(struct render_context *ctx, uint32_t fontcolor) {
|
||||||
|
@ -265,6 +266,7 @@ static uint32_t render_status_block(struct render_context *ctx,
|
||||||
|
|
||||||
uint32_t bg_color = block->urgent
|
uint32_t bg_color = block->urgent
|
||||||
? config->colors.urgent_workspace.background : block->background;
|
? config->colors.urgent_workspace.background : block->background;
|
||||||
|
ctx->has_transparency |= (bg_color & 0xFF) != 0xFF;
|
||||||
if (bg_color) {
|
if (bg_color) {
|
||||||
render_sharp_rectangle(cairo, bg_color, x_pos, y_pos,
|
render_sharp_rectangle(cairo, bg_color, x_pos, y_pos,
|
||||||
block_width, render_height);
|
block_width, render_height);
|
||||||
|
@ -291,11 +293,11 @@ static uint32_t render_status_block(struct render_context *ctx,
|
||||||
}
|
}
|
||||||
|
|
||||||
double offset = 0;
|
double offset = 0;
|
||||||
if (strncmp(block->align, "left", 4) == 0) {
|
if (has_prefix(block->align, "left")) {
|
||||||
offset = x_pos;
|
offset = x_pos;
|
||||||
} else if (strncmp(block->align, "right", 5) == 0) {
|
} else if (has_prefix(block->align, "right")) {
|
||||||
offset = x_pos + width - text_width;
|
offset = x_pos + width - text_width;
|
||||||
} else if (strncmp(block->align, "center", 6) == 0) {
|
} else if (has_prefix(block->align, "center")) {
|
||||||
offset = x_pos + (width - text_width) / 2;
|
offset = x_pos + (width - text_width) / 2;
|
||||||
}
|
}
|
||||||
double text_y = height / 2.0 - text_height / 2.0;
|
double text_y = height / 2.0 - text_height / 2.0;
|
||||||
|
@ -574,6 +576,7 @@ static uint32_t render_binding_mode_indicator(struct render_context *ctx,
|
||||||
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
|
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
|
||||||
cairo_set_source_u32(cairo, config->colors.binding_mode.background);
|
cairo_set_source_u32(cairo, config->colors.binding_mode.background);
|
||||||
ctx->background_color = config->colors.binding_mode.background;
|
ctx->background_color = config->colors.binding_mode.background;
|
||||||
|
ctx->has_transparency |= (config->colors.binding_mode.background & 0xFF) != 0xFF;
|
||||||
cairo_rectangle(cairo, x, 0, width, height);
|
cairo_rectangle(cairo, x, 0, width, height);
|
||||||
cairo_fill(cairo);
|
cairo_fill(cairo);
|
||||||
|
|
||||||
|
@ -653,6 +656,7 @@ static uint32_t render_workspace_button(struct render_context *ctx,
|
||||||
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
|
cairo_set_operator(cairo, CAIRO_OPERATOR_SOURCE);
|
||||||
cairo_set_source_u32(cairo, box_colors.background);
|
cairo_set_source_u32(cairo, box_colors.background);
|
||||||
ctx->background_color = box_colors.background;
|
ctx->background_color = box_colors.background;
|
||||||
|
ctx->has_transparency |= (box_colors.background & 0xFF) != 0xFF;
|
||||||
cairo_rectangle(cairo, *x, 0, width, height);
|
cairo_rectangle(cairo, *x, 0, width, height);
|
||||||
cairo_fill(cairo);
|
cairo_fill(cairo);
|
||||||
|
|
||||||
|
@ -760,10 +764,12 @@ void render_frame(struct swaybar_output *output) {
|
||||||
background_color = output->bar->config->colors.background;
|
background_color = output->bar->config->colors.background;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct render_context ctx = { 0 };
|
struct render_context ctx = {
|
||||||
ctx.output = output;
|
.output = output,
|
||||||
// initial background color used for deciding the best way to antialias text
|
// initial background color used for deciding the best way to antialias text
|
||||||
ctx.background_color = background_color;
|
.background_color = background_color,
|
||||||
|
.has_transparency = (background_color & 0xFF) != 0xFF,
|
||||||
|
};
|
||||||
|
|
||||||
cairo_surface_t *recorder = cairo_recording_surface_create(
|
cairo_surface_t *recorder = cairo_recording_surface_create(
|
||||||
CAIRO_CONTENT_COLOR_ALPHA, NULL);
|
CAIRO_CONTENT_COLOR_ALPHA, NULL);
|
||||||
|
@ -834,8 +840,7 @@ void render_frame(struct swaybar_output *output) {
|
||||||
wl_surface_damage(output->surface, 0, 0,
|
wl_surface_damage(output->surface, 0, 0,
|
||||||
output->width, output->height);
|
output->width, output->height);
|
||||||
|
|
||||||
uint32_t bg_alpha = background_color & 0xFF;
|
if (!ctx.has_transparency) {
|
||||||
if (bg_alpha == 0xFF) {
|
|
||||||
struct wl_region *region =
|
struct wl_region *region =
|
||||||
wl_compositor_create_region(output->bar->compositor);
|
wl_compositor_create_region(output->bar->compositor);
|
||||||
wl_region_add(region, 0, 0, INT32_MAX, INT32_MAX);
|
wl_region_add(region, 0, 0, INT32_MAX, INT32_MAX);
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include "cairo_util.h"
|
#include "cairo_util.h"
|
||||||
#include "list.h"
|
#include "list.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
|
#include "stringop.h"
|
||||||
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
|
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
|
||||||
|
|
||||||
// TODO menu
|
// TODO menu
|
||||||
|
@ -161,7 +162,7 @@ static int get_property_callback(sd_bus_message *msg, void *data,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(prop, "Status") == 0 || (sni->status && (sni->status[0] == 'N' ?
|
if (strcmp(prop, "Status") == 0 || (sni->status && (sni->status[0] == 'N' ?
|
||||||
prop[0] == 'A' : strncmp(prop, "Icon", 4) == 0))) {
|
prop[0] == 'A' : has_prefix(prop, "Icon")))) {
|
||||||
set_sni_dirty(sni);
|
set_sni_dirty(sni);
|
||||||
}
|
}
|
||||||
cleanup:
|
cleanup:
|
||||||
|
@ -364,7 +365,7 @@ static void handle_click(struct swaybar_sni *sni, int x, int y,
|
||||||
method = "ContextMenu";
|
method = "ContextMenu";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strncmp(method, "Scroll", strlen("Scroll")) == 0) {
|
if (has_prefix(method, "Scroll")) {
|
||||||
char dir = method[strlen("Scroll")];
|
char dir = method[strlen("Scroll")];
|
||||||
char *orientation = (dir == 'U' || dir == 'D') ? "vertical" : "horizontal";
|
char *orientation = (dir == 'U' || dir == 'D') ? "vertical" : "horizontal";
|
||||||
int sign = (dir == 'U' || dir == 'L') ? -1 : 1;
|
int sign = (dir == 'U' || dir == 'L') ? -1 : 1;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <cairo.h>
|
#include <cairo.h>
|
||||||
|
#include <poll.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
@ -90,9 +91,16 @@ void destroy_tray(struct swaybar_tray *tray) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void tray_in(int fd, short mask, void *data) {
|
void tray_in(int fd, short mask, void *data) {
|
||||||
sd_bus *bus = data;
|
struct swaybar *bar = data;
|
||||||
int ret;
|
int ret;
|
||||||
while ((ret = sd_bus_process(bus, NULL)) > 0) {
|
|
||||||
|
if (mask & (POLLHUP | POLLERR)) {
|
||||||
|
sway_log(SWAY_ERROR, "D-Bus connection closed unexpectedly");
|
||||||
|
bar->running = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while ((ret = sd_bus_process(bar->tray->bus, NULL)) > 0) {
|
||||||
// This space intentionally left blank
|
// This space intentionally left blank
|
||||||
}
|
}
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
|
|
|
@ -31,13 +31,15 @@ static int handle_lost_service(sd_bus_message *msg,
|
||||||
struct swaybar_watcher *watcher = data;
|
struct swaybar_watcher *watcher = data;
|
||||||
for (int idx = 0; idx < watcher->items->length; ++idx) {
|
for (int idx = 0; idx < watcher->items->length; ++idx) {
|
||||||
char *id = watcher->items->items[idx];
|
char *id = watcher->items->items[idx];
|
||||||
int cmp_res = using_standard_protocol(watcher) ?
|
bool cmp_res = using_standard_protocol(watcher) ?
|
||||||
cmp_id(id, service) : strncmp(id, service, strlen(service));
|
cmp_id(id, service) == 0 : has_prefix(id, service);
|
||||||
if (cmp_res == 0) {
|
if (cmp_res) {
|
||||||
sway_log(SWAY_DEBUG, "Unregistering Status Notifier Item '%s'", id);
|
sway_log(SWAY_DEBUG, "Unregistering Status Notifier Item '%s'", id);
|
||||||
list_del(watcher->items, idx--);
|
list_del(watcher->items, idx--);
|
||||||
sd_bus_emit_signal(watcher->bus, obj_path, watcher->interface,
|
sd_bus_emit_signal(watcher->bus, obj_path, watcher->interface,
|
||||||
"StatusNotifierItemUnregistered", "s", id);
|
"StatusNotifierItemUnregistered", "s", id);
|
||||||
|
sd_bus_emit_properties_changed(watcher->bus, obj_path, watcher->interface,
|
||||||
|
"RegisteredStatusNotifierItems", NULL);
|
||||||
free(id);
|
free(id);
|
||||||
if (using_standard_protocol(watcher)) {
|
if (using_standard_protocol(watcher)) {
|
||||||
break;
|
break;
|
||||||
|
@ -50,6 +52,10 @@ static int handle_lost_service(sd_bus_message *msg,
|
||||||
sway_log(SWAY_DEBUG, "Unregistering Status Notifier Host '%s'", service);
|
sway_log(SWAY_DEBUG, "Unregistering Status Notifier Host '%s'", service);
|
||||||
free(watcher->hosts->items[idx]);
|
free(watcher->hosts->items[idx]);
|
||||||
list_del(watcher->hosts, idx);
|
list_del(watcher->hosts, idx);
|
||||||
|
if (watcher->hosts->length == 0) {
|
||||||
|
sd_bus_emit_properties_changed(watcher->bus, obj_path, watcher->interface,
|
||||||
|
"IsStatusNotifierHostRegistered", NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,6 +88,8 @@ static int register_sni(sd_bus_message *msg, void *data, sd_bus_error *error) {
|
||||||
if (list_seq_find(watcher->items, cmp_id, id) == -1) {
|
if (list_seq_find(watcher->items, cmp_id, id) == -1) {
|
||||||
sway_log(SWAY_DEBUG, "Registering Status Notifier Item '%s'", id);
|
sway_log(SWAY_DEBUG, "Registering Status Notifier Item '%s'", id);
|
||||||
list_add(watcher->items, id);
|
list_add(watcher->items, id);
|
||||||
|
sd_bus_emit_properties_changed(watcher->bus, obj_path, watcher->interface,
|
||||||
|
"RegisteredStatusNotifierItems", NULL);
|
||||||
sd_bus_emit_signal(watcher->bus, obj_path, watcher->interface,
|
sd_bus_emit_signal(watcher->bus, obj_path, watcher->interface,
|
||||||
"StatusNotifierItemRegistered", "s", id);
|
"StatusNotifierItemRegistered", "s", id);
|
||||||
} else {
|
} else {
|
||||||
|
@ -104,6 +112,10 @@ static int register_host(sd_bus_message *msg, void *data, sd_bus_error *error) {
|
||||||
if (list_seq_find(watcher->hosts, cmp_id, service) == -1) {
|
if (list_seq_find(watcher->hosts, cmp_id, service) == -1) {
|
||||||
sway_log(SWAY_DEBUG, "Registering Status Notifier Host '%s'", service);
|
sway_log(SWAY_DEBUG, "Registering Status Notifier Host '%s'", service);
|
||||||
list_add(watcher->hosts, strdup(service));
|
list_add(watcher->hosts, strdup(service));
|
||||||
|
if (watcher->hosts->length == 1) {
|
||||||
|
sd_bus_emit_properties_changed(watcher->bus, obj_path, watcher->interface,
|
||||||
|
"IsStatusNotifierHostRegistered", NULL);
|
||||||
|
}
|
||||||
sd_bus_emit_signal(watcher->bus, obj_path, watcher->interface,
|
sd_bus_emit_signal(watcher->bus, obj_path, watcher->interface,
|
||||||
"StatusNotifierHostRegistered", "");
|
"StatusNotifierHostRegistered", "");
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -193,7 +193,7 @@ static void pretty_print_output(json_object *o) {
|
||||||
json_object_object_get_ex(o, "current_workspace", &ws);
|
json_object_object_get_ex(o, "current_workspace", &ws);
|
||||||
json_object_object_get_ex(o, "non_desktop", &non_desktop);
|
json_object_object_get_ex(o, "non_desktop", &non_desktop);
|
||||||
json_object *make, *model, *serial, *scale, *scale_filter, *subpixel,
|
json_object *make, *model, *serial, *scale, *scale_filter, *subpixel,
|
||||||
*transform, *max_render_time, *adaptive_sync_status;
|
*transform, *max_render_time, *adaptive_sync_status, *allow_tearing;
|
||||||
json_object_object_get_ex(o, "make", &make);
|
json_object_object_get_ex(o, "make", &make);
|
||||||
json_object_object_get_ex(o, "model", &model);
|
json_object_object_get_ex(o, "model", &model);
|
||||||
json_object_object_get_ex(o, "serial", &serial);
|
json_object_object_get_ex(o, "serial", &serial);
|
||||||
|
@ -203,6 +203,7 @@ static void pretty_print_output(json_object *o) {
|
||||||
json_object_object_get_ex(o, "transform", &transform);
|
json_object_object_get_ex(o, "transform", &transform);
|
||||||
json_object_object_get_ex(o, "max_render_time", &max_render_time);
|
json_object_object_get_ex(o, "max_render_time", &max_render_time);
|
||||||
json_object_object_get_ex(o, "adaptive_sync_status", &adaptive_sync_status);
|
json_object_object_get_ex(o, "adaptive_sync_status", &adaptive_sync_status);
|
||||||
|
json_object_object_get_ex(o, "allow_tearing", &allow_tearing);
|
||||||
json_object *x, *y;
|
json_object *x, *y;
|
||||||
json_object_object_get_ex(rect, "x", &x);
|
json_object_object_get_ex(rect, "x", &x);
|
||||||
json_object_object_get_ex(rect, "y", &y);
|
json_object_object_get_ex(rect, "y", &y);
|
||||||
|
@ -256,6 +257,9 @@ static void pretty_print_output(json_object *o) {
|
||||||
|
|
||||||
printf(" Adaptive sync: %s\n",
|
printf(" Adaptive sync: %s\n",
|
||||||
json_object_get_string(adaptive_sync_status));
|
json_object_get_string(adaptive_sync_status));
|
||||||
|
|
||||||
|
printf(" Allow tearing: %s\n",
|
||||||
|
json_object_get_boolean(allow_tearing) ? "yes" : "no");
|
||||||
} else {
|
} else {
|
||||||
printf(
|
printf(
|
||||||
"Output %s '%s %s %s' (disabled)\n",
|
"Output %s '%s %s %s' (disabled)\n",
|
||||||
|
@ -326,6 +330,10 @@ static void pretty_print_tree(json_object *obj, int indent) {
|
||||||
const char *instance = json_object_get_string(json_object_object_get(window_props_obj, "instance"));
|
const char *instance = json_object_get_string(json_object_object_get(window_props_obj, "instance"));
|
||||||
const char *class = json_object_get_string(json_object_object_get(window_props_obj, "class"));
|
const char *class = json_object_get_string(json_object_object_get(window_props_obj, "class"));
|
||||||
int x11_id = json_object_get_int(json_object_object_get(obj, "window"));
|
int x11_id = json_object_get_int(json_object_object_get(obj, "window"));
|
||||||
|
const char *foreign_toplevel_id = json_object_get_string(json_object_object_get(obj, "foreign_toplevel_identifier"));
|
||||||
|
const char *sandbox_engine = json_object_get_string(json_object_object_get(obj, "sandbox_engine"));
|
||||||
|
const char *sandbox_app_id = json_object_get_string(json_object_object_get(obj, "sandbox_app_id"));
|
||||||
|
const char *sandbox_instance_id = json_object_get_string(json_object_object_get(obj, "sandbox_instance_id"));
|
||||||
|
|
||||||
printf(" (%s, pid: %d", shell, pid);
|
printf(" (%s, pid: %d", shell, pid);
|
||||||
if (app_id != NULL) {
|
if (app_id != NULL) {
|
||||||
|
@ -340,6 +348,18 @@ static void pretty_print_tree(json_object *obj, int indent) {
|
||||||
if (x11_id != 0) {
|
if (x11_id != 0) {
|
||||||
printf(", X11 window: 0x%X", x11_id);
|
printf(", X11 window: 0x%X", x11_id);
|
||||||
}
|
}
|
||||||
|
if (foreign_toplevel_id != NULL) {
|
||||||
|
printf(", foreign_toplevel_id: \"%s\"", foreign_toplevel_id);
|
||||||
|
}
|
||||||
|
if (sandbox_engine != NULL) {
|
||||||
|
printf(", sandbox_engine: \"%s\"", sandbox_engine);
|
||||||
|
}
|
||||||
|
if (sandbox_app_id != NULL) {
|
||||||
|
printf(", sandbox_app_id: \"%s\"", sandbox_app_id);
|
||||||
|
}
|
||||||
|
if (sandbox_instance_id != NULL) {
|
||||||
|
printf(", sandbox_instance_id: \"%s\"", sandbox_instance_id);
|
||||||
|
}
|
||||||
printf(")");
|
printf(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -324,7 +324,9 @@ static void output_scale(void *data, struct wl_output *output,
|
||||||
swaynag_output->scale = factor;
|
swaynag_output->scale = factor;
|
||||||
if (swaynag_output->swaynag->output == swaynag_output) {
|
if (swaynag_output->swaynag->output == swaynag_output) {
|
||||||
swaynag_output->swaynag->scale = swaynag_output->scale;
|
swaynag_output->swaynag->scale = swaynag_output->scale;
|
||||||
update_all_cursors(swaynag_output->swaynag);
|
if (!swaynag_output->swaynag->cursor_shape_manager) {
|
||||||
|
update_all_cursors(swaynag_output->swaynag);
|
||||||
|
}
|
||||||
render_frame(swaynag_output->swaynag);
|
render_frame(swaynag_output->swaynag);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue