Merge branch 'master' into master

This commit is contained in:
Radical 2023-11-24 15:31:37 +01:00 committed by GitHub
commit c6066ac7e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
135 changed files with 1612 additions and 1948 deletions

1
.gitignore vendored
View file

@ -6,6 +6,7 @@ bin/
test/
build/
build-*/
.cache/
.lvimrc
config-debug
wayland-*-protocol.*

91
README.ar.md Normal file
View file

@ -0,0 +1,91 @@
# sway
sway
هو مدير للمجموعات المركبة لـ[Wayland] متوافق مع [i3] -
إقرأ [الأسئلة الشائعة](https://github.com/swaywm/sway/wiki)
انضم الى [قناة IRC](https://web.libera.chat/gamja/?channels=#sway)
## تواقيع الإصدار
تٌوقع الإصدارات بـواسطة [E88F5E48] و تُنشر على [GitHub](https://github.com/swaywm/sway/releases)
## التثبيت
### بإستخدام الحزم
يتوفر Sway للعديد من التوزيعات، حاول تثبيت حزمة "sway" لتوزيعتك
### التجميع من المصدر
إطلع على [صفحة الويكي هذه](https://github.com/swaywm/sway/wiki/Development-Setup) إذا أردت بناء الـHEAD من sway و wlroots لأغراض الفحص والتطوير
تثبيت اللوازم:
* meson \*
* [wlroots]
* wayland
* wayland-protocols \*
* pcre2
* json-c
* pango
* cairo
* gdk-pixbuf2 (optional: system tray)
* [scdoc] (optional: man pages) \*
* git (optional: version info) \*
_\* Compile-time dep_
نفذ هذه الأوامر:
meson build/
ninja -C build/
sudo ninja -C build/ install
## الإعدادات
إذا كنت بالفعل تستخدم i3، فعليك نسخ إعدادات i3 لديك إلى `~/.config/sway/config` وسوف تعمل تلقائياً.
و إلا عليك نسخ ملف الإعدادات النموذج إلى `config/sway/config` الموجود عادةً في `/etc/sway/config.`
## التشغيل
شغل `sway` بإستخدام أمر TTY.
قد يعمل بعض مدراء العرض مع أنهم غير مدعومون من sway
(gdm مثلاً يعمل بشكل جيد إلى حد ما)
[en]: https://github.com/swaywm/sway#readme
[ar]: README.ar.md
[cs]: README.cs.md
[de]: README.de.md
[dk]: README.dk.md
[es]: README.es.md
[fr]: README.fr.md
[ge]: README.ge.md
[gr]: README.gr.md
[hi]: README.hi.md
[hu]: README.hu.md
[ir]: README.ir.md
[it]: README.it.md
[ja]: README.ja.md
[ko]: README.ko.md
[nl]: README.nl.md
[no]: README.no.md
[pl]: README.pl.md
[pt]: README.pt.md
[ro]: README.ro.md
[ru]: README.ru.md
[sv]: README.sv.md
[tr]: README.tr.md
[uk]: README.uk.md
[zh-CN]: README.zh-CN.md
[zh-TW]: README.zh-TW.md
[i3]: https://i3wm.org/
[Wayland]: http://wayland.freedesktop.org/
[FAQ]: https://github.com/swaywm/sway/wiki
[IRC channel]: https://web.libera.chat/gamja/?channels=#sway
[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
[GitHub releases]: https://github.com/swaywm/sway/releases
[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup
[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
[scdoc]: https://git.sr.ht/~sircmpwn/scdoc

View file

@ -43,12 +43,6 @@ Spusťte tyto příkazy:
ninja -C build/
sudo ninja -C build/ install
Na systémech bez logind či seatd musíte binární soubor sway nastavit jako suid:
sudo chmod a+s /usr/local/bin/sway
Sway svá root oprávnění zruší krátce po spuštění.
## Konfigurace
Pokud již používáte i3, zkopírujte svou konfiguraci i3 do `~/.config/sway/config`

View file

@ -5,13 +5,13 @@
Sway ist ein [i3](https://i3wm.org/)-kompatibler [Wayland]-Compositor. Lies die [FAQ]. Tritt dem [IRC Channel] bei (#sway on irc.libera.chat; Englisch).
## Signaturen
Jedes Release wird mit dem PGP-Schlüssel [E88F5E48] signiert und auf GitHub veröffentlicht.
Jedes Release wird mit dem PGP-Schlüssel [E88F5E48] signiert und auf GitHub veröffentlicht signiert und [auf GitHub][GitHub releases] veröffentlicht..
## Installation
### Mit der Paketverwaltung
Sway kann in vielen Distributionen direkt durch die Paketverwaltung installiert werden. Das Paket sollte "sway" heißen. Falls es kein solches Paket gibt, kannst du im [Wiki](https://github.com/swaywm/sway/wiki/Unsupported-packages) (englisch) nach mehr Informationen bezüglich deiner Distribution suchen.
Falls du sway für deine eigene Distribution als Paket bereitstellen möchtest, solltest du die Entwickler per IRC oder E-Mail (sir@cmpwn.com) kontaktieren.
### Über die Paketverwaltung
Sway kann in vielen Distributionen direkt durch die Paketverwaltung installiert werden. Versuche einfach das Packet "sway" zu installieren.
### Quellcode selbst kompilieren
@ -26,8 +26,8 @@ sway benötigt die folgenden Pakete:
* pango
* cairo
* gdk-pixbuf2 (Optional, wird für das Benachrichtigungsfeld (System Tray) benötigt)
* [scdoc]\* (Optional, wird für die Dokumentation (Man Pages) benötigt)
* git\*
* [scdoc] (Optional, wird für die Dokumentation (Man Pages) benötigt)\*
* git (Optional: Versionsinfo)\*
_\*Werden nur während des Kompilierens benötigt_
@ -37,12 +37,6 @@ Führe die folgenden Befehle aus:
ninja -C build
sudo ninja -C build install
Falls dein System nicht logind benutzt, musst du sway noch die passenden Berechtigungen geben:
sudo chmod a+s /usr/local/bin/sway
Sway läuft nur in der Startphase mit Root-Rechten.
## Konfiguration
Falls du von i3 migrierst, kannst du deine Konfigurationsdatei nach `~/.config/sway/config` kopieren und die Einstellungen sollten ohne Weiteres funktionieren. Ansonsten kannst du die Beispielkonfiguration, die normalerweise in `/etc/sway/config` liegt, nach `~/.config/sway/config` kopieren. Die Dokumentation zur Konfigurationsdatei findest du in `man 5 sway`.

View file

@ -47,12 +47,6 @@ Kør følgende kommandoer:
ninja -C build
sudo ninja -C build install
På systemer uden logind eller seatd skal du sætte SUID bit på sway filen:
sudo chmod a+s /usr/local/bin/sway
Sway dropper 'root' tilladelser kort efter opstart.
## Konfiguration
Hvis du allerede bruger i3 kan du bare kopiere din i3 konfiguration til

View file

@ -46,12 +46,6 @@ Desde su consola, ejecute las órdenes:
ninja -C build
sudo ninja -C build install
En sistemas sin `logind`, necesitará cambiar los permisos del archivo compilado de sway:
sudo chmod a+s /usr/local/bin/sway
Sway abandonará los permisos de super-usuario al poco de arrancar.
## Configuración
Si ya utiliza i3, copie su archivo de configuración de i3 a `~/.config/sway/config` y

View file

@ -53,12 +53,6 @@ Exécutez ces commandes :
ninja -C build
sudo ninja -C build install
Sur les systèmes sans logind, vous devez suid le binaire de sway :
sudo chmod a+s /usr/local/bin/sway
Sway se débarassera des permissions *root* peu de temps après le démarrage.
## Configuration
Si vous utilisez déjà i3, copiez votre configuration i3 vers

61
README.ge.md Normal file
View file

@ -0,0 +1,61 @@
# sway
sway არის [i3]-თავსებადი [Wayland]-ის კომპოზიტორი. მეტი ინფორმაციისთვის იხილეთ
[FAQ]. დაუკავშირდით [IRC არხს][IRC channel] \(#sway irc.libera.chat-ზე).
## გამოშვების ხელმოწერები
გამოშვებები ხელმოწერილია [E88F5E48]-ით და გამოქვეყნებულია [GitHub-ზე][GitHub releases].
## ინსტალაცია
### რეპოზიტორიიდან
Sway არის ხელმისაწვდომი ბევრი დისტრიბუტაციისთვის. ცადეთ "sway" პაკეტის ინსტალაცია თქვენთვის.
### კოდის კომპილაცია
იხილეთ [ეს ვიკი გვერდი][Development setup] თუ გინდათ რომ ააწყოთ sway და wlroots სატესტოდ ან დეველოპმენტისთვის.
დააინსტალირეთ დამოკიდებულებები:
* meson \*
* [wlroots]
* wayland
* wayland-protocols \*
* pcre2
* json-c
* pango
* cairo
* gdk-pixbuf2 (ასევე არჩევითია: system tray)
* [scdoc] (ასევე არჩევითია: man pages) \*
* git (ასევე არჩევითია: version info) \*
_\* Compile-time dep_
გაუშვით ეს ბრძანებები:
meson build/
ninja -C build/
sudo ninja -C build/ install
## კონფიგურაცია
თუ უკვე იყენებთ i3-ს, მაშინ დააკოპირე i3 კონფიგურაცია და ჩასვი `~/.config/sway/config`
და უპრობლემოდ იმუშავებს პირდაპირ. წინააღმდეგ შემთხვევაში კონფიგურაციის ნიმუში ჩააკოპირეთ აქ: `~/.config/sway/config`. კომპიგურაციის ნიმუში ხშირ შემთხვევაში არის `/etc/sway/config`.
გაუშვი `man 5 sway` კონპიგურაციაზე ინფორმაციის მისაღებად.
## გაშვება
გაუშვი `sway` TTY-ისთვის. ზოგიერთმა ლოგინ მენეჯერმა შეიძლება იმუშავოს, მაგრამ არ
არის მხარდაჭერილი sway-სგან (როგორც წესი კარგად მუშაობს gdm).
[i3]: https://i3wm.org/
[Wayland]: http://wayland.freedesktop.org/
[FAQ]: https://github.com/swaywm/sway/wiki
[IRC channel]: https://web.libera.chat/gamja/?channels=#sway
[E88F5E48]: https://keys.openpgp.org/search?q=34FF9526CFEF0E97A340E2E40FDE7BE0E88F5E48
[GitHub releases]: https://github.com/swaywm/sway/releases
[Development setup]: https://github.com/swaywm/sway/wiki/Development-Setup
[wlroots]: https://gitlab.freedesktop.org/wlroots/wlroots
[scdoc]: https://git.sr.ht/~sircmpwn/scdoc

View file

@ -46,12 +46,6 @@ _\*Compile-time dep_
ninja -C build/
sudo ninja -C build/ install
Σε συστήματα χωρίς logind ή seatd, πρέπει να κάνετε suid το sway binary:
sudo chmod a+s /usr/local/bin/sway
Το Sway θα κάνει drop root δικαιώματα λίγο μετά την εκκίνηση.
## Configuration
Εάν ήδη χρησιμοποιήτε το i3, αντιγράψτε το i3 config σας στο `~/.config/sway/config` και

View file

@ -50,13 +50,6 @@ _\* Compilation के समय आवश्यक_
ninja -C build/
sudo ninja -C build/ install
उन systems पर जिनमें ना तो logind है, ना ही seatd है, आपको sway की binary
को suid करना पडेगा:
sudo chmod a+s /usr/local/bin/sway
Sway अपनी root अनुमतियां प्रारंभ होने के कुछ ही देर बाद छोड़ देगी।
## Configuration
अगर आप पहले से ही i3 का उपयोग करते हैं तो अपने i3 config को

View file

@ -46,13 +46,6 @@ Futtasd ezeket a parancsokat:
ninja -C build
sudo ninja -C build install
Ha `logind` nélküli rendszert használsz, akkor be kell állítanod a `suid` bitet
a futtaható állományon:
sudo chmod a+s /usr/local/bin/sway
A Sway indulás után nem sokkal el fogja engedni a root jogosultságait.
## Konfiguráció
Ha előzőleg i3-mat használtál, akkor átmásolhatod az i3 beállításaidat a

View file

@ -47,12 +47,6 @@ _\*نیازمندی‌های زمان کامپایل برنامه_
ninja -C build
sudo ninja -C build install
روی سیستم‌های بدون logind، باید فرمان زیر را برای suid کردن باینری sway اجرا کنید:
sudo chmod a+s /usr/local/bin/sway
‏sway پس از startup مجوزهای دسترسی root را رها می‌کند.
### شخصی سازی و تنظیمات
اگر در حال حاضر از i3 استفاده می‌کنید، تنظیمات i3 خودتان را در فایل `~/.config/sway/config` کپی کنید و بدون نیاز به تغییر کار خواهد کرد. در غیر این‌صورت، فایل نمونه تنظیمات را استفاده کنید. این فایل عموما در `/etc/sway/config` قرار دارد. برای آگاهی بیشتر `man 5 sway` را اجرا کنید.

View file

@ -44,13 +44,6 @@ Esegui questi comandi:
ninja -C build/
sudo ninja -C build/ install
Nei sistemi in cui non sono disponibili né logind né seatd, è necessario
impostare il permesso suid al binario di sway:
sudo chmod a+s /usr/local/bin/sway
Sway rinuncerà ai permessi di root poco dopo l'avvio.
## Configurazione
Se hai già usato i3, copia il tuo file di configurazione in

View file

@ -45,12 +45,6 @@ _\*컴파일 떄 필요_
ninja -C build
sudo ninja -C build install
logind를 사용하고 있지 않는 시스템에서는, 바이너리에 suid를 설정할 필요가 있습니다:
sudo chmod a+s /usr/local/bin/sway
Sway는 시작 후에 root 권한을 drop할 것 입니다.
## 설정
i3를 이미 사용 중이라면, i3 config을 `~/.config/sway/config`로 복사하세요.

View file

@ -1,6 +1,6 @@
# sway
**[English][en]** - [Česky][cs] - [Deutsch][de] - [Dansk][dk] - [Español][es] - [Français][fr] - [Ελληνικά][gr] - [हिन्दी][hi] - [Magyar][hu] - [فارسی][ir] - [Italiano][it] - [日本語][ja] - [한국어][ko] - [Nederlands][nl] - [Norsk][no] - [Polski][pl] - [Português][pt] - [Română][ro] - [Русский][ru] - [Svenska][sv] - [Türkçe][tr] - [Українська][uk] - [中文-简体][zh-CN] - [中文-繁體][zh-TW]
**[English][en]** - [عربي][ar] - [Česky][cs] - [Deutsch][de] - [Dansk][dk] - [Español][es] - [Français][fr] - [ქართული][ge] - [Ελληνικά][gr] - [हिन्दी][hi] - [Magyar][hu] - [فارسی][ir] - [Italiano][it] - [日本語][ja] - [한국어][ko] - [Nederlands][nl] - [Norsk][no] - [Polski][pl] - [Português][pt] - [Română][ro] - [Русский][ru] - [Svenska][sv] - [Türkçe][tr] - [Українська][uk] - [中文-简体][zh-CN] - [中文-繁體][zh-TW]
sway is an [i3]-compatible [Wayland] compositor. Read the [FAQ]. Join the
[IRC channel] \(#sway on irc.libera.chat).
@ -43,12 +43,6 @@ Run these commands:
ninja -C build/
sudo ninja -C build/ install
On systems without logind nor seatd, you need to suid the sway binary:
sudo chmod a+s /usr/local/bin/sway
Sway will drop root permissions shortly after startup.
## Configuration
If you already use i3, then copy your i3 config to `~/.config/sway/config` and
@ -62,11 +56,13 @@ Run `sway` from a TTY. Some display managers may work but are not supported by
sway (gdm is known to work fairly well).
[en]: https://github.com/swaywm/sway#readme
[ar]: README.ar.md
[cs]: README.cs.md
[de]: README.de.md
[dk]: README.dk.md
[es]: README.es.md
[fr]: README.fr.md
[ge]: README.ge.md
[gr]: README.gr.md
[hi]: README.hi.md
[hu]: README.hu.md

View file

@ -46,12 +46,6 @@ Voer deze opdrachten uit:
ninja -C build
sudo ninja -C build install
Op systemen zonder logind, moet je bij het binaire bestand het suid bit instellen:
sudo chmod a+s /usr/local/bin/sway
Sway zal root-rechten kort na het opstarten loslaten.
## Configuratie
Als je al i3 gebruikt, kopieer dan je i3-configuratie naar `~/.config/sway/config` en

View file

@ -46,12 +46,6 @@ Wykonaj następujące polecenia:
ninja -C build
sudo ninja -C build install
Na systemach bez logind należy wykonać polecenie suid na pliku wykonywalnym sway:
sudo chmod a+s /usr/local/bin/sway
Sway pozbędzie się uprawnień roota tuż po wystartowaniu.
## Konfiguracja
Jeśli już korzystasz z i3, skopiuj swoją konfigurację i3 do katalogu `~/.config/sway/config` i

View file

@ -48,12 +48,6 @@ Execute esses comandos:
ninja -C build
sudo ninja -C build install
Em sistemas sem logind, você precisa preparar o binário do sway:
sudo chmod a+s /usr/local/bin/sway
O sway perderá as privilégios de de root logo após o início do sistema.
## Configuração
Se você já utiliza o i3, então copie os seus arquivos de configuração para `~/.config/sway/config` e

View file

@ -45,14 +45,6 @@ Rulați aceste comenzi:
sudo ninja -C build install
```
Pe sisteme fără logind, trebuie să folosiți următoarea comandă pentru a marca binarul de Sway ca suid:
```
sudo chmod a+s /usr/local/bin/sway
```
Imediat după pornire, Sway va renunța la permisiunile de root.
## Configurare
Dacă folosiți deja i3, copiați fișierul de configurare din i3 în `~/.config/sway/config`, și va funcționa fără a necesita nici o modificare. In caz contrar, copiați exemplul de configurare (disponibil de obicei în `/etc/sway/config`) în `~/.config/sway/config`.

View file

@ -47,12 +47,6 @@ _\*Зависимости для сборки_
ninja -C build
sudo ninja -C build install
На системах без logind вам понадобится добавить suid к файлу программы sway:
sudo chmod a+s /usr/local/bin/sway
sway сбросит root-права при запуске.
## Настройка
Если вы уже используете i3, скопируйте ваш конфигурационный файл i3 в `~/.config/sway/config`, и

View file

@ -41,12 +41,6 @@ Kör dessa kommandon:
ninja -C build/
sudo ninja -C build/ install
På system utan logind eller seatd måste du ge sways exekverbara fil root-privilegier:
sudo chmod a+s /usr/local/bin/sway
Sway kommer att överge sina root-privilegier kort efter uppstart.
## Konfiguration
Ifall du redan använder i3 så kan du kopiera din konfigurationsfil till `~/.config/sway/config` och det kommer då att fungera som det ska.

View file

@ -43,12 +43,6 @@ _\*Derleme-anı bağımlılıkları_
ninja -C build
sudo ninja -C build install
logind olmayan sistemlerde, sway ikilisine (binary) izin vermeniz (suid) gerekir:
sudo chmod a+s /usr/local/bin/sway
Sway, başlangıçtan kısa bir süre sonra kök(root) izinlerini bırakacaktır.
## Yapılandırma
Zaten i3 kullanıyorsanız, i3 yapılandırmanızı `~/.config/sway/config` konumuna kopyalayın ve kutudan çıktığı gibi çalışacaktır. Aksi takdirde, örnek yapılandırma dosyasını `~/.config/sway/config` konumuna kopyalayın. Genellikle `/etc/sway/config` konumunda bulunur.

View file

@ -57,12 +57,6 @@ _\*Лише для компіляції_
ninja -C build
sudo ninja -C build install
На системах без logind, необхідно встановити біт SUID на виконуваний файл sway:
sudo chmod a+s /usr/local/bin/sway
Sway втратить права доступу root незабаром після запуску.
## Налаштування
Якщо ви вже використовуєте i3, скопіюйте свій файл налаштувань

View file

@ -41,12 +41,6 @@ _\*编译时依赖_
ninja -C build/
sudo ninja -C build/ install
在没有logind或seatd的系统上, 你需要给sway二进制文件设置suid:
sudo chmod a+s /usr/local/bin/sway
启动后Sway会尽快放弃root权限。
## 配置
如果你已经在使用i3直接复制i3配置文件到 `~/.config/sway/config`,这是开箱即用的。或者,你可以复制配置样例到`~/.config/sway/config`。它通常位于 `/etc/sway/config`

View file

@ -46,12 +46,6 @@ _\*編譯時相依_
ninja -C build
sudo ninja -C build install
在沒有 logind 的系統上,你需要為 sway 的執行檔加上 suid。
sudo chmod a+s /usr/local/bin/sway
Sway 在啟動不久後就會放棄 root 權限。
## 設定檔
如果你已經在使用 i3你可以直接將你的 i3 設定檔複製到 `~/.config/sway/config` 然後就能直接使用。

View file

@ -12,23 +12,6 @@
const uint8_t GESTURE_FINGERS_ANY = 0;
// Helper to easily allocate and format string
static char *strformat(const char *format, ...) {
va_list args;
va_start(args, format);
int length = vsnprintf(NULL, 0, format, args) + 1;
va_end(args);
char *result = malloc(length);
if (result) {
va_start(args, format);
vsnprintf(result, length, format, args);
va_end(args);
}
return result;
}
char *gesture_parse(const char *input, struct gesture *output) {
// Clear output in case of failure
output->type = GESTURE_TYPE_NONE;
@ -38,7 +21,7 @@ char *gesture_parse(const char *input, struct gesture *output) {
// Split input type, fingers and directions
list_t *split = split_string(input, ":");
if (split->length < 1 || split->length > 3) {
return strformat(
return format_str(
"expected <gesture>[:<fingers>][:direction], got %s",
input);
}
@ -51,8 +34,8 @@ char *gesture_parse(const char *input, struct gesture *output) {
} else if (strcmp(split->items[0], "swipe") == 0) {
output->type = GESTURE_TYPE_SWIPE;
} else {
return strformat("expected hold|pinch|swipe, got %s",
split->items[0]);
return format_str("expected hold|pinch|swipe, got %s",
(const char *)split->items[0]);
}
// Parse optional arguments
@ -67,7 +50,7 @@ char *gesture_parse(const char *input, struct gesture *output) {
next = split->length == 3 ? split->items[2] : NULL;
} else if (split->length == 3) {
// Fail here if argument can only be finger count
return strformat("expected 1-9, got %s", next);
return format_str("expected 1-9, got %s", next);
}
// If there is an argument left, try to parse as direction
@ -95,7 +78,7 @@ char *gesture_parse(const char *input, struct gesture *output) {
} else if (strcmp(item, "counterclockwise") == 0) {
output->directions |= GESTURE_DIRECTION_COUNTERCLOCKWISE;
} else {
return strformat("expected direction, got %s", item);
return format_str("expected direction, got %s", item);
}
}
list_free_items_and_destroy(directions);
@ -163,7 +146,7 @@ static char *gesture_directions_to_string(uint32_t directions) {
if (!result) {
result = strdup(name);
} else {
char *new = strformat("%s+%s", result, name);
char *new = format_str("%s+%s", result, name);
free(result);
result = new;
}
@ -179,7 +162,7 @@ static char *gesture_directions_to_string(uint32_t directions) {
char *gesture_to_string(struct gesture *gesture) {
char *directions = gesture_directions_to_string(gesture->directions);
char *result = strformat("%s:%u:%s",
char *result = format_str("%s:%u:%s",
gesture_type_string(gesture->type),
gesture->fingers, directions);
free(directions);

View file

@ -1,7 +1,6 @@
lib_sway_common = static_library(
'sway-common',
files(
'background-image.c',
'cairo.c',
'gesture.c',
'ipc-client.c',
@ -14,7 +13,6 @@ lib_sway_common = static_library(
),
dependencies: [
cairo,
gdk_pixbuf,
pango,
pangocairo,
wayland_client.partial_dependency(compile_args: true)

View file

@ -84,18 +84,11 @@ void get_text_size(cairo_t *cairo, const PangoFontDescription *desc, int *width,
int *baseline, double scale, bool markup, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
// Add one since vsnprintf excludes null terminator.
int length = vsnprintf(NULL, 0, fmt, args) + 1;
char *buf = vformat_str(fmt, args);
va_end(args);
char *buf = malloc(length);
if (buf == NULL) {
sway_log(SWAY_ERROR, "Failed to allocate memory");
return;
}
va_start(args, fmt);
vsnprintf(buf, length, fmt, args);
va_end(args);
PangoLayout *layout = get_pango_layout(cairo, desc, buf, scale, markup);
pango_cairo_update_layout(cairo, layout);
@ -104,6 +97,7 @@ void get_text_size(cairo_t *cairo, const PangoFontDescription *desc, int *width,
*baseline = pango_layout_get_baseline(layout) / PANGO_SCALE;
}
g_object_unref(layout);
free(buf);
}
@ -125,18 +119,11 @@ void render_text(cairo_t *cairo, const PangoFontDescription *desc,
double scale, bool markup, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
// Add one since vsnprintf excludes null terminator.
int length = vsnprintf(NULL, 0, fmt, args) + 1;
char *buf = vformat_str(fmt, args);
va_end(args);
char *buf = malloc(length);
if (buf == NULL) {
sway_log(SWAY_ERROR, "Failed to allocate memory");
return;
}
va_start(args, fmt);
vsnprintf(buf, length, fmt, args);
va_end(args);
PangoLayout *layout = get_pango_layout(cairo, desc, buf, scale, markup);
cairo_font_options_t *fo = cairo_font_options_create();
@ -146,5 +133,6 @@ void render_text(cairo_t *cairo, const PangoFontDescription *desc,
pango_cairo_update_layout(cairo, layout);
pango_cairo_show_layout(cairo, layout);
g_object_unref(layout);
free(buf);
}

View file

@ -1,5 +1,6 @@
#define _POSIX_C_SOURCE 200809L
#include <ctype.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
@ -328,3 +329,35 @@ bool expand_path(char **path) {
wordfree(&p);
return true;
}
char *vformat_str(const char *fmt, va_list args) {
char *str = NULL;
va_list args_copy;
va_copy(args_copy, args);
int len = vsnprintf(NULL, 0, fmt, args);
if (len < 0) {
sway_log_errno(SWAY_ERROR, "vsnprintf(\"%s\") failed", fmt);
goto out;
}
str = malloc(len + 1);
if (str == NULL) {
sway_log_errno(SWAY_ERROR, "malloc() failed");
goto out;
}
vsnprintf(str, len + 1, fmt, args_copy);
out:
va_end(args_copy);
return str;
}
char *format_str(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
char *str = vformat_str(fmt, args);
va_end(args);
return str;
}

View file

@ -205,7 +205,7 @@ bar {
# When the status_command prints a new line to stdout, swaybar updates.
# The default just shows the current date and time.
status_command while date +'%Y-%m-%d %I:%M:%S %p'; do sleep 1; done
status_command while date +'%Y-%m-%d %X'; do sleep 1; done
colors {
statusline #ffffff

View file

@ -1,124 +0,0 @@
#!/usr/bin/python
# This script requires i3ipc-python package (install it from a system package manager
# or pip).
# It adds icons to the workspace name for each open window.
# Set your keybindings like this: set $workspace1 workspace number 1
# Add your icons to WINDOW_ICONS.
# Based on https://github.com/maximbaz/dotfiles/blob/master/bin/i3-autoname-workspaces
import argparse
import i3ipc
import logging
import re
import signal
import sys
WINDOW_ICONS = {
"firefox": "",
}
DEFAULT_ICON = "󰀏"
def icon_for_window(window):
name = None
if window.app_id is not None and len(window.app_id) > 0:
name = window.app_id.lower()
elif window.window_class is not None and len(window.window_class) > 0:
name = window.window_class.lower()
if name in WINDOW_ICONS:
return WINDOW_ICONS[name]
logging.info("No icon available for window with name: %s" % str(name))
return DEFAULT_ICON
def rename_workspaces(ipc):
for workspace in ipc.get_tree().workspaces():
name_parts = parse_workspace_name(workspace.name)
icon_tuple = ()
for w in workspace:
if w.app_id is not None or w.window_class is not None:
icon = icon_for_window(w)
if not ARGUMENTS.duplicates and icon in icon_tuple:
continue
icon_tuple += (icon,)
name_parts["icons"] = " ".join(icon_tuple) + " "
new_name = construct_workspace_name(name_parts)
ipc.command('rename workspace "%s" to "%s"' % (workspace.name, new_name))
def undo_window_renaming(ipc):
for workspace in ipc.get_tree().workspaces():
name_parts = parse_workspace_name(workspace.name)
name_parts["icons"] = None
new_name = construct_workspace_name(name_parts)
ipc.command('rename workspace "%s" to "%s"' % (workspace.name, new_name))
ipc.main_quit()
sys.exit(0)
def parse_workspace_name(name):
return re.match(
"(?P<num>[0-9]+):?(?P<shortname>\w+)? ?(?P<icons>.+)?", name
).groupdict()
def construct_workspace_name(parts):
new_name = str(parts["num"])
if parts["shortname"] or parts["icons"]:
new_name += ":"
if parts["shortname"]:
new_name += parts["shortname"]
if parts["icons"]:
new_name += " " + parts["icons"]
return new_name
if __name__ == "__main__":
parser = argparse.ArgumentParser(
description="This script automatically changes the workspace name in sway depending on your open applications."
)
parser.add_argument(
"--duplicates",
"-d",
action="store_true",
help="Set it when you want an icon for each instance of the same application per workspace.",
)
parser.add_argument(
"--logfile",
"-l",
type=str,
default="/tmp/sway-autoname-workspaces.log",
help="Path for the logfile.",
)
args = parser.parse_args()
global ARGUMENTS
ARGUMENTS = args
logging.basicConfig(
level=logging.INFO,
filename=ARGUMENTS.logfile,
filemode="w",
format="%(message)s",
)
ipc = i3ipc.Connection()
for sig in [signal.SIGINT, signal.SIGTERM]:
signal.signal(sig, lambda signal, frame: undo_window_renaming(ipc))
def window_event_handler(ipc, e):
if e.change in ["new", "close", "move"]:
rename_workspaces(ipc)
ipc.on("window", window_event_handler)
rename_workspaces(ipc)
ipc.main()

View file

@ -1,168 +0,0 @@
#!/bin/sh
## Grimshot: a helper for screenshots within sway
## Requirements:
## - `grim`: screenshot utility for wayland
## - `slurp`: to select an area
## - `swaymsg`: to read properties of current window
## - `wl-copy`: clipboard utility
## - `jq`: json utility to parse swaymsg output
## - `notify-send`: to show notifications
## Those are needed to be installed, if unsure, run `grimshot check`
##
## See `man 1 grimshot` or `grimshot usage` for further details.
getTargetDirectory() {
test -f "${XDG_CONFIG_HOME:-$HOME/.config}/user-dirs.dirs" && \
. "${XDG_CONFIG_HOME:-$HOME/.config}/user-dirs.dirs"
echo "${XDG_SCREENSHOTS_DIR:-${XDG_PICTURES_DIR:-$HOME}}"
}
NOTIFY=no
CURSOR=
while [ $# -gt 0 ]; do
key="$1"
case $key in
-n|--notify)
NOTIFY=yes
shift # past argument
;;
-c|--cursor)
CURSOR=yes
shift # past argument
;;
*) # unknown option
break # done with parsing --flags
;;
esac
done
ACTION=${1:-usage}
SUBJECT=${2:-screen}
FILE=${3:-$(getTargetDirectory)/$(date -Ins).png}
if [ "$ACTION" != "save" ] && [ "$ACTION" != "copy" ] && [ "$ACTION" != "check" ]; then
echo "Usage:"
echo " grimshot [--notify] [--cursor] (copy|save) [active|screen|output|area|window] [FILE|-]"
echo " grimshot check"
echo " grimshot usage"
echo ""
echo "Commands:"
echo " copy: Copy the screenshot data into the clipboard."
echo " save: Save the screenshot to a regular file or '-' to pipe to STDOUT."
echo " check: Verify if required tools are installed and exit."
echo " usage: Show this message and exit."
echo ""
echo "Targets:"
echo " active: Currently active window."
echo " screen: All visible outputs."
echo " output: Currently active output."
echo " area: Manually select a region."
echo " window: Manually select a window."
exit
fi
notify() {
notify-send -t 3000 -a grimshot "$@"
}
notifyOk() {
[ "$NOTIFY" = "no" ] && return
TITLE=${2:-"Screenshot"}
MESSAGE=${1:-"OK"}
notify "$TITLE" "$MESSAGE"
}
notifyError() {
if [ $NOTIFY = "yes" ]; then
TITLE=${2:-"Screenshot"}
MESSAGE=${1:-"Error taking screenshot with grim"}
notify -u critical "$TITLE" "$MESSAGE"
else
echo "$1"
fi
}
die() {
MSG=${1:-Bye}
notifyError "Error: $MSG"
exit 2
}
check() {
COMMAND=$1
if command -v "$COMMAND" > /dev/null 2>&1; then
RESULT="OK"
else
RESULT="NOT FOUND"
fi
echo " $COMMAND: $RESULT"
}
takeScreenshot() {
FILE=$1
GEOM=$2
OUTPUT=$3
if [ -n "$OUTPUT" ]; then
grim ${CURSOR:+-c} -o "$OUTPUT" "$FILE" || die "Unable to invoke grim"
elif [ -z "$GEOM" ]; then
grim ${CURSOR:+-c} "$FILE" || die "Unable to invoke grim"
else
grim ${CURSOR:+-c} -g "$GEOM" "$FILE" || die "Unable to invoke grim"
fi
}
if [ "$ACTION" = "check" ] ; then
echo "Checking if required tools are installed. If something is missing, install it to your system and make it available in PATH..."
check grim
check slurp
check swaymsg
check wl-copy
check jq
check notify-send
exit
elif [ "$SUBJECT" = "area" ] ; then
GEOM=$(slurp -d)
# Check if user exited slurp without selecting the area
if [ -z "$GEOM" ]; then
exit 1
fi
WHAT="Area"
elif [ "$SUBJECT" = "active" ] ; then
FOCUSED=$(swaymsg -t get_tree | jq -r 'recurse(.nodes[]?, .floating_nodes[]?) | select(.focused)')
GEOM=$(echo "$FOCUSED" | jq -r '.rect | "\(.x),\(.y) \(.width)x\(.height)"')
APP_ID=$(echo "$FOCUSED" | jq -r '.app_id')
WHAT="$APP_ID window"
elif [ "$SUBJECT" = "screen" ] ; then
GEOM=""
WHAT="Screen"
elif [ "$SUBJECT" = "output" ] ; then
GEOM=""
OUTPUT=$(swaymsg -t get_outputs | jq -r '.[] | select(.focused)' | jq -r '.name')
WHAT="$OUTPUT"
elif [ "$SUBJECT" = "window" ] ; then
GEOM=$(swaymsg -t get_tree | jq -r '.. | select(.pid? and .visible?) | .rect | "\(.x),\(.y) \(.width)x\(.height)"' | slurp)
# Check if user exited slurp without selecting the area
if [ -z "$GEOM" ]; then
exit 1
fi
WHAT="Window"
else
die "Unknown subject to take a screen shot from" "$SUBJECT"
fi
if [ "$ACTION" = "copy" ] ; then
takeScreenshot - "$GEOM" "$OUTPUT" | wl-copy --type image/png || die "Clipboard error"
notifyOk "$WHAT copied to buffer"
else
if takeScreenshot "$FILE" "$GEOM" "$OUTPUT"; then
TITLE="Screenshot of $SUBJECT"
MESSAGE=$(basename "$FILE")
notifyOk "$MESSAGE" "$TITLE"
echo "$FILE"
else
notifyError "Error taking screenshot with grim"
fi
fi

View file

@ -1,109 +0,0 @@
.\" Generated by scdoc 1.11.2
.\" Complete documentation for this program is not available as a GNU info page
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.nh
.ad l
.\" Begin generated content:
.TH "grimshot" "1" "2022-03-31"
.P
.SH NAME
.P
grimshot - a helper for screenshots within sway
.P
.SH SYNOPSIS
.P
\fBgrimshot\fR [--notify] [--cursor] (copy|save) [TARGET] [FILE]
.br
\fBgrimshot\fR check
.br
\fBgrimshot\fR usage
.P
.SH OPTIONS
.P
\fB--notify\fR
.RS 4
Show notifications to the user that a screenshot has been taken.\&
.P
.RE
\fB--cursor\fR
.RS 4
Include cursors in the screenshot.\&
.P
.RE
\fBsave\fR
.RS 4
Save the screenshot into a regular file.\& Grimshot will write images
files to \fBXDG_SCREENSHOTS_DIR\fR if this is set (or defined
in \fBuser-dirs.\&dir\fR), or otherwise fall back to \fBXDG_PICTURES_DIR\fR.\&
Set FILE to '\&-'\& to pipe the output to STDOUT.\&
.P
.RE
\fBcopy\fR
.RS 4
Copy the screenshot data (as image/png) into the clipboard.\&
.P
.RE
.SH DESCRIPTION
.P
Grimshot is an easy-to-use screenshot utility for sway.\& It provides a
convenient interface over grim, slurp and jq, and supports storing the
screenshot either directly to the clipboard using wl-copy or to a file.\&
.P
.SH EXAMPLES
.P
An example usage pattern is to add these bindings to your sway config:
.P
.nf
.RS 4
# Screenshots:
# Super+P: Current window
# Super+Shift+p: Select area
# Super+Alt+p Current output
# Super+Ctrl+p Select a window
bindsym Mod4+p exec grimshot save active
bindsym Mod4+Shift+p exec grimshot save area
bindsym Mod4+Mod1+p exec grimshot save output
bindsym Mod4+Ctrl+p exec grimshot save window
.fi
.RE
.P
.SH TARGETS
.P
grimshot can capture the following named targets:
.P
\fIactive\fR
.RS 4
Captures the currently active window.\&
.P
.RE
\fIscreen\fR
.RS 4
Captures the entire screen.\& This includes all visible outputs.\&
.P
.RE
\fIarea\fR
.RS 4
Allows manually selecting a rectangular region, and captures that.\&
.P
.RE
\fIwindow\fR
.RS 4
Allows manually selecting a single window (by clicking on it), and
captures it.\&
.P
.RE
\fIoutput\fR
.RS 4
Captures the currently active output.\&
.P
.RE
.SH OUTPUT
.P
Grimshot will print the filename of the captured screenshot to stdout if called
with the \fIsave\fR subcommand.\&
.P
.SH SEE ALSO
.P
\fBgrim\fR(1)

View file

@ -1,80 +0,0 @@
grimshot(1)
# NAME
grimshot - a helper for screenshots within sway
# SYNOPSIS
*grimshot* [--notify] [--cursor] (copy|save) [TARGET] [FILE]++
*grimshot* check++
*grimshot* usage
# OPTIONS
*--notify*
Show notifications to the user that a screenshot has been taken.
*--cursor*
Include cursors in the screenshot.
*save*
Save the screenshot into a regular file. Grimshot will write image
files to *XDG_SCREENSHOTS_DIR* if this is set (or defined
in *user-dirs.dir*), or otherwise fall back to *XDG_PICTURES_DIR*.
Set FILE to '-' to pipe the output to STDOUT.
*copy*
Copy the screenshot data (as image/png) into the clipboard.
# DESCRIPTION
Grimshot is an easy-to-use screenshot utility for sway. It provides a
convenient interface over grim, slurp and jq, and supports storing the
screenshot either directly to the clipboard using wl-copy or to a file.
# EXAMPLES
An example usage pattern is to add these bindings to your sway config:
```
# Screenshots:
# Super+P: Current window
# Super+Shift+p: Select area
# Super+Alt+p Current output
# Super+Ctrl+p Select a window
bindsym Mod4+p exec grimshot save active
bindsym Mod4+Shift+p exec grimshot save area
bindsym Mod4+Mod1+p exec grimshot save output
bindsym Mod4+Ctrl+p exec grimshot save window
```
# TARGETS
grimshot can capture the following named targets:
_active_
Captures the currently active window.
_screen_
Captures the entire screen. This includes all visible outputs.
_area_
Allows manually selecting a rectangular region, and captures that.
_window_
Allows manually selecting a single window (by clicking on it), and
captures it.
_output_
Captures the currently active output.
# OUTPUT
Grimshot will print the filename of the captured screenshot to stdout if called
with the _save_ subcommand.
# SEE ALSO
*grim*(1)

View file

@ -1,69 +0,0 @@
#!/usr/bin/python
# This script requires i3ipc-python package (install it from a system package manager
# or pip).
# It makes inactive windows transparent. Use `transparency_val` variable to control
# transparency strength in range of 0…1 or use the command line argument -o.
import argparse
import i3ipc
import signal
import sys
from functools import partial
def on_window_focus(inactive_opacity, ipc, event):
global prev_focused
global prev_workspace
focused_workspace = ipc.get_tree().find_focused()
if focused_workspace == None:
return
focused = event.container
workspace = focused_workspace.workspace().num
if focused.id != prev_focused.id: # https://github.com/swaywm/sway/issues/2859
focused.command("opacity 1")
if workspace == prev_workspace:
prev_focused.command("opacity " + inactive_opacity)
prev_focused = focused
prev_workspace = workspace
def remove_opacity(ipc):
for workspace in ipc.get_tree().workspaces():
for w in workspace:
w.command("opacity 1")
ipc.main_quit()
sys.exit(0)
if __name__ == "__main__":
transparency_val = "0.80"
parser = argparse.ArgumentParser(
description="This script allows you to set the transparency of unfocused windows in sway."
)
parser.add_argument(
"--opacity",
"-o",
type=str,
default=transparency_val,
help="set opacity value in range 0...1",
)
args = parser.parse_args()
ipc = i3ipc.Connection()
prev_focused = None
prev_workspace = ipc.get_tree().find_focused().workspace().num
for window in ipc.get_tree():
if window.focused:
prev_focused = window
else:
window.command("opacity " + args.opacity)
for sig in [signal.SIGINT, signal.SIGTERM]:
signal.signal(sig, lambda signal, frame: remove_opacity(ipc))
ipc.on("window::focus", partial(on_window_focus, args.opacity))
ipc.main()

View file

@ -1,20 +0,0 @@
#ifndef _SWAY_BACKGROUND_IMAGE_H
#define _SWAY_BACKGROUND_IMAGE_H
#include "cairo_util.h"
enum background_mode {
BACKGROUND_MODE_STRETCH,
BACKGROUND_MODE_FILL,
BACKGROUND_MODE_FIT,
BACKGROUND_MODE_CENTER,
BACKGROUND_MODE_TILE,
BACKGROUND_MODE_SOLID_COLOR,
BACKGROUND_MODE_INVALID,
};
enum background_mode parse_background_mode(const char *mode);
cairo_surface_t *load_background_image(const char *path);
void render_background_image(cairo_t *cairo, cairo_surface_t *image,
enum background_mode mode, int buffer_width, int buffer_height);
#endif

View file

@ -5,6 +5,7 @@
#include <stdint.h>
#include <cairo.h>
#include <pango/pangocairo.h>
#include "stringop.h"
/**
* Utility function which escape characters a & < > ' ".
@ -16,9 +17,9 @@ size_t escape_markup_text(const char *src, char *dest);
PangoLayout *get_pango_layout(cairo_t *cairo, const PangoFontDescription *desc,
const char *text, double scale, bool markup);
void get_text_size(cairo_t *cairo, const PangoFontDescription *desc, int *width, int *height,
int *baseline, double scale, bool markup, const char *fmt, ...);
int *baseline, double scale, bool markup, const char *fmt, ...) _SWAY_ATTRIB_PRINTF(8, 9);
void get_text_metrics(const PangoFontDescription *desc, int *height, int *baseline);
void render_text(cairo_t *cairo, PangoFontDescription *desc,
double scale, bool markup, const char *fmt, ...);
double scale, bool markup, const char *fmt, ...) _SWAY_ATTRIB_PRINTF(5, 6);
#endif

View file

@ -5,6 +5,12 @@
#include <stddef.h>
#include "list.h"
#ifdef __GNUC__
#define _SWAY_ATTRIB_PRINTF(start, end) __attribute__((format(printf, start, end)))
#else
#define _SWAY_ATTRIB_PRINTF(start, end)
#endif
void strip_whitespace(char *str);
void strip_quotes(char *str);
@ -31,4 +37,7 @@ char *argsep(char **stringp, const char *delim, char *matched_delim);
// Expand a path using shell replacements such as $HOME and ~
bool expand_path(char **path);
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);
#endif

View file

@ -3,6 +3,7 @@
#include <wlr/util/edges.h>
#include "config.h"
#include "stringop.h"
struct sway_container;
@ -76,7 +77,7 @@ struct cmd_results *config_commands_command(char *exec);
/**
* Allocates a cmd_results object.
*/
struct cmd_results *cmd_results_new(enum cmd_status status, const char *error, ...);
struct cmd_results *cmd_results_new(enum cmd_status status, const char *error, ...) _SWAY_ATTRIB_PRINTF(2, 3);
/**
* Frees a cmd_results object.
*/
@ -265,6 +266,7 @@ sway_cmd input_cmd_scroll_factor;
sway_cmd input_cmd_repeat_delay;
sway_cmd input_cmd_repeat_rate;
sway_cmd input_cmd_scroll_button;
sway_cmd input_cmd_scroll_button_lock;
sway_cmd input_cmd_scroll_method;
sway_cmd input_cmd_tap;
sway_cmd input_cmd_tap_button_map;

View file

@ -12,6 +12,7 @@
#include "../include/config.h"
#include "gesture.h"
#include "list.h"
#include "stringop.h"
#include "swaynag.h"
#include "tree/container.h"
#include "sway/input/tablet.h"
@ -160,6 +161,7 @@ struct input_config {
int repeat_delay;
int repeat_rate;
int scroll_button;
int scroll_button_lock;
int scroll_method;
int send_events;
int tap;
@ -625,7 +627,7 @@ void run_deferred_bindings(void);
/**
* Adds a warning entry to the swaynag instance used for errors.
*/
void config_add_swaynag_warning(char *fmt, ...);
void config_add_swaynag_warning(char *fmt, ...) _SWAY_ATTRIB_PRINTF(1, 2);
/**
* Free config struct

View file

@ -43,6 +43,7 @@ struct criteria {
struct pattern *window_role;
enum atom_name window_type;
#endif
bool all;
bool floating;
bool tiling;
char urgent; // 'l' for latest or 'o' for oldest

View file

@ -1,8 +1,6 @@
#ifndef _SWAY_DESKTOP_IDLE_INHIBIT_V1_H
#define _SWAY_DESKTOP_IDLE_INHIBIT_V1_H
#include <wlr/types/wlr_idle_inhibit_v1.h>
#include <wlr/types/wlr_idle.h>
#include "sway/server.h"
enum sway_idle_inhibit_mode {
INHIBIT_IDLE_APPLICATION, // Application set inhibitor (when visible)
@ -16,12 +14,9 @@ struct sway_idle_inhibit_manager_v1 {
struct wlr_idle_inhibit_manager_v1 *wlr_manager;
struct wl_listener new_idle_inhibitor_v1;
struct wl_list inhibitors;
struct wlr_idle *idle;
};
struct sway_idle_inhibitor_v1 {
struct sway_idle_inhibit_manager_v1 *manager;
struct wlr_idle_inhibitor_v1 *wlr_inhibitor;
struct sway_view *view;
enum sway_idle_inhibit_mode mode;
@ -33,8 +28,7 @@ struct sway_idle_inhibitor_v1 {
bool sway_idle_inhibit_v1_is_active(
struct sway_idle_inhibitor_v1 *inhibitor);
void sway_idle_inhibit_v1_check_active(
struct sway_idle_inhibit_manager_v1 *manager);
void sway_idle_inhibit_v1_check_active(void);
void sway_idle_inhibit_v1_user_inhibitor_register(struct sway_view *view,
enum sway_idle_inhibit_mode mode);
@ -48,6 +42,6 @@ struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_application_inhibitor_for_vi
void sway_idle_inhibit_v1_user_inhibitor_destroy(
struct sway_idle_inhibitor_v1 *inhibitor);
struct sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create(
struct wl_display *wl_display, struct wlr_idle *idle);
bool sway_idle_inhibit_manager_v1_init(void);
#endif

View file

@ -35,7 +35,6 @@ struct sway_cursor {
pixman_region32_t confine; // invalid if active_constraint == NULL
bool active_confine_requires_warp;
struct wlr_pointer_gestures_v1 *pointer_gestures;
struct wl_listener hold_begin;
struct wl_listener hold_end;
struct wl_listener pinch_begin;
@ -53,6 +52,7 @@ struct sway_cursor {
struct wl_listener touch_down;
struct wl_listener touch_up;
struct wl_listener touch_cancel;
struct wl_listener touch_motion;
struct wl_listener touch_frame;
bool simulating_pointer_from_touch;
@ -145,4 +145,6 @@ uint32_t get_mouse_button(const char *name, char **error);
const char *get_mouse_button_name(uint32_t button);
void handle_request_set_cursor_shape(struct wl_listener *listener, void *data);
#endif

View file

@ -1,7 +1,6 @@
#ifndef _SWAY_INPUT_INPUT_MANAGER_H
#define _SWAY_INPUT_INPUT_MANAGER_H
#include <libinput.h>
#include <wlr/types/wlr_input_inhibitor.h>
#include <wlr/types/wlr_keyboard_shortcuts_inhibit_v1.h>
#include <wlr/types/wlr_virtual_keyboard_v1.h>
#include <wlr/types/wlr_virtual_pointer_v1.h>
@ -21,10 +20,10 @@ struct sway_input_manager {
struct wl_list devices;
struct wl_list seats;
struct wlr_input_inhibit_manager *inhibit;
struct wlr_keyboard_shortcuts_inhibit_manager_v1 *keyboard_shortcuts_inhibit;
struct wlr_virtual_keyboard_manager_v1 *virtual_keyboard;
struct wlr_virtual_pointer_manager_v1 *virtual_pointer;
struct wlr_pointer_gestures_v1 *pointer_gestures;
struct wl_listener new_input;
struct wl_listener inhibit_activate;
@ -44,7 +43,7 @@ void input_manager_configure_xcursor(void);
void input_manager_apply_input_config(struct input_config *input_config);
void input_manager_configure_all_inputs(void);
void input_manager_configure_all_input_mappings(void);
void input_manager_reset_input(struct sway_input_device *input_device);

View file

@ -12,6 +12,7 @@
#include "sway/input/text_input.h"
struct sway_seat;
struct render_context;
struct sway_seatop_impl {
void (*button)(struct sway_seat *seat, uint32_t time_msec,
@ -43,14 +44,15 @@ struct sway_seatop_impl {
struct wlr_touch_up_event *event);
void (*touch_down)(struct sway_seat *seat,
struct wlr_touch_down_event *event, double lx, double ly);
void (*touch_cancel)(struct sway_seat *seat,
struct wlr_touch_cancel_event *event);
void (*tablet_tool_motion)(struct sway_seat *seat,
struct sway_tablet_tool *tool, uint32_t time_msec);
void (*tablet_tool_tip)(struct sway_seat *seat, struct sway_tablet_tool *tool,
uint32_t time_msec, enum wlr_tablet_tool_tip_state state);
void (*end)(struct sway_seat *seat);
void (*unref)(struct sway_seat *seat, struct sway_container *con);
void (*render)(struct sway_seat *seat, struct sway_output *output,
const pixman_region32_t *damage);
void (*render)(struct sway_seat *seat, struct render_context *ctx);
bool allow_set_cursor;
};
@ -102,8 +104,9 @@ struct sway_seat {
struct sway_workspace *workspace;
char *prev_workspace_name; // for workspace back_and_forth
// If the focused layer is set, views cannot receive keyboard focus
struct wlr_layer_surface_v1 *focused_layer;
// If the exclusive layer is set, views cannot receive keyboard focus
bool has_exclusive_layer;
// If exclusive_client is set, no other clients will receive input events
struct wl_client *exclusive_client;
@ -165,6 +168,9 @@ void seat_add_device(struct sway_seat *seat,
void seat_configure_device(struct sway_seat *seat,
struct sway_input_device *device);
void seat_configure_device_mapping(struct sway_seat *seat,
struct sway_input_device *input_device);
void seat_reset_device(struct sway_seat *seat,
struct sway_input_device *input_device);
@ -338,6 +344,9 @@ void seatop_touch_up(struct sway_seat *seat,
void seatop_touch_down(struct sway_seat *seat,
struct wlr_touch_down_event *event, double lx, double ly);
void seatop_touch_cancel(struct sway_seat *seat,
struct wlr_touch_cancel_event *event);
void seatop_rebase(struct sway_seat *seat, uint32_t time_msec);
/**
@ -356,8 +365,7 @@ void seatop_unref(struct sway_seat *seat, struct sway_container *con);
* Instructs a seatop to render anything that it needs to render
* (eg. dropzone for move-tiling)
*/
void seatop_render(struct sway_seat *seat, struct sway_output *output,
const pixman_region32_t *damage);
void seatop_render(struct sway_seat *seat, struct render_context *ctx);
bool seatop_allows_set_cursor(struct sway_seat *seat);

View file

@ -8,7 +8,7 @@
/**
* The relay structure manages the relationship between text-input and
* input_method interfaces on a given seat. Multiple text-input interfaces may
* be bound to a relay, but at most one will be focused (reveiving events) at
* be bound to a relay, but at most one will be focused (receiving events) at
* a time. At most one input-method interface may be bound to the seat. The
* relay manages life cycle of both sides. When both sides are present and
* focused, the relay passes messages between them.

View file

@ -55,6 +55,10 @@ struct sway_layer_subsurface {
};
struct sway_output;
struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
struct wlr_surface *surface);
void arrange_layers(struct sway_output *output);
struct sway_layer_surface *layer_from_wlr_layer_surface_v1(

View file

@ -33,8 +33,6 @@ struct sway_output {
int width, height; // transformed buffer size
enum wl_output_subpixel detected_subpixel;
enum scale_filter_mode scale_filter;
// last applied mode when the output is powered off
struct wlr_output_mode *current_mode;
bool enabling, enabled;
list_t *workspaces;
@ -57,6 +55,7 @@ struct sway_output {
uint32_t refresh_nsec;
int max_render_time; // In milliseconds
struct wl_event_source *repaint_timer;
bool gamma_lut_changed;
};
struct sway_output_non_desktop {
@ -65,6 +64,14 @@ struct sway_output_non_desktop {
struct wl_listener destroy;
};
struct render_context {
struct sway_output *output;
struct wlr_renderer *renderer;
const pixman_region32_t *output_damage;
struct wlr_render_pass *pass;
};
struct sway_output *output_create(struct wlr_output *wlr_output);
void output_destroy(struct sway_output *output);
@ -96,6 +103,9 @@ void output_damage_box(struct sway_output *output, struct wlr_box *box);
void output_damage_whole_container(struct sway_output *output,
struct sway_container *con);
bool output_match_name_or_id(struct sway_output *output,
const char *name_or_id);
// this ONLY includes the enabled outputs
struct sway_output *output_by_name_or_id(const char *name_or_id);
@ -112,7 +122,7 @@ bool output_has_opaque_overlay_layer_surface(struct sway_output *output);
struct sway_workspace *output_get_active_workspace(struct sway_output *output);
void output_render(struct sway_output *output, pixman_region32_t *damage);
void output_render(struct render_context *ctx);
void output_surface_for_each_surface(struct sway_output *output,
struct wlr_surface *surface, double ox, double oy,
@ -165,8 +175,7 @@ void output_get_box(struct sway_output *output, struct wlr_box *box);
enum sway_container_layout output_get_default_layout(
struct sway_output *output);
void render_rect(struct sway_output *output,
const pixman_region32_t *output_damage, const struct wlr_box *_box,
void render_rect(struct render_context *ctx, const struct wlr_box *_box,
float color[static 4]);
void premultiply_alpha(float color[4], float opacity);
@ -177,6 +186,8 @@ 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_test(struct wl_listener *listener, void *data);

View file

@ -21,6 +21,7 @@
#include <wlr/types/wlr_xdg_shell.h>
#include "config.h"
#include "list.h"
#include "sway/desktop/idle_inhibit_v1.h"
#if HAVE_XWAYLAND
#include "sway/xwayland.h"
#endif
@ -51,15 +52,14 @@ struct sway_server {
struct wl_listener new_output;
struct wl_listener output_layout_change;
struct wlr_idle *idle;
struct wlr_idle_notifier_v1 *idle_notifier_v1;
struct sway_idle_inhibit_manager_v1 *idle_inhibit_manager_v1;
struct sway_idle_inhibit_manager_v1 idle_inhibit_manager_v1;
struct wlr_layer_shell_v1 *layer_shell;
struct wl_listener layer_shell_surface;
struct wlr_xdg_shell *xdg_shell;
struct wl_listener xdg_shell_surface;
struct wl_listener xdg_shell_toplevel;
struct wlr_tablet_manager_v2 *tablet_v2;
@ -91,6 +91,9 @@ struct sway_server {
struct wl_listener output_manager_apply;
struct wl_listener output_manager_test;
struct wlr_gamma_control_manager_v1 *gamma_control_manager_v1;
struct wl_listener gamma_control_set_gamma;
struct {
bool locked;
struct wlr_session_lock_manager_v1 *manager;
@ -111,11 +114,17 @@ struct sway_server {
struct wlr_text_input_manager_v3 *text_input;
struct wlr_foreign_toplevel_manager_v1 *foreign_toplevel_manager;
struct wlr_content_type_manager_v1 *content_type_manager_v1;
struct wlr_data_control_manager_v1 *data_control_manager_v1;
struct wlr_screencopy_manager_v1 *screencopy_manager_v1;
struct wlr_export_dmabuf_manager_v1 *export_dmabuf_manager_v1;
struct wlr_security_context_manager_v1 *security_context_manager_v1;
struct wlr_xdg_activation_v1 *xdg_activation_v1;
struct wl_listener xdg_activation_v1_request_activate;
struct wl_listener xdg_activation_v1_new_token;
struct wl_listener request_set_cursor_shape;
struct wl_list pending_launcher_ctxs; // launcher_ctx::link
// The timeout for transactions, after which a transaction is applied
@ -167,7 +176,7 @@ void handle_new_output(struct wl_listener *listener, void *data);
void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data);
void handle_layer_shell_surface(struct wl_listener *listener, void *data);
void sway_session_lock_init(void);
void handle_xdg_shell_surface(struct wl_listener *listener, void *data);
void handle_xdg_shell_toplevel(struct wl_listener *listener, void *data);
#if HAVE_XWAYLAND
void handle_xwayland_surface(struct wl_listener *listener, void *data);
#endif

View file

@ -1,6 +1,7 @@
#ifndef _SWAY_SWAYNAG_H
#define _SWAY_SWAYNAG_H
#include <wayland-server-core.h>
#include "stringop.h"
struct swaynag_instance {
struct wl_client *client;
@ -21,7 +22,7 @@ bool swaynag_spawn(const char *swaynag_command,
// Write a log message to swaynag->fd[1]. This will fail when swaynag->detailed
// is false.
void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag,
const char *fmt, ...);
const char *fmt, ...) _SWAY_ATTRIB_PRINTF(3, 4);
// If swaynag->detailed, close swaynag->fd[1] so swaynag displays
void swaynag_show(struct swaynag_instance *swaynag);

View file

@ -41,7 +41,7 @@ struct sway_root {
} events;
};
struct sway_root *root_create(void);
struct sway_root *root_create(struct wl_display *display);
void root_destroy(struct sway_root *root);

View file

@ -160,6 +160,8 @@ struct sway_xwayland_view {
struct wl_listener set_window_type;
struct wl_listener set_hints;
struct wl_listener set_decorations;
struct wl_listener associate;
struct wl_listener dissociate;
struct wl_listener map;
struct wl_listener unmap;
struct wl_listener destroy;
@ -177,6 +179,8 @@ struct sway_xwayland_unmanaged {
struct wl_listener request_fullscreen;
struct wl_listener commit;
struct wl_listener set_geometry;
struct wl_listener associate;
struct wl_listener dissociate;
struct wl_listener map;
struct wl_listener unmap;
struct wl_listener destroy;
@ -222,6 +226,7 @@ struct sway_xdg_popup {
struct wlr_xdg_popup *wlr_xdg_popup;
struct wl_listener surface_commit;
struct wl_listener new_popup;
struct wl_listener destroy;
};

View file

@ -16,4 +16,6 @@ struct sway_xdg_decoration {
struct sway_xdg_decoration *xdg_decoration_from_surface(
struct wlr_surface *surface);
void set_xdg_decoration_mode(struct sway_xdg_decoration *deco);
#endif

View file

@ -4,6 +4,7 @@
#include "config.h"
#include "input.h"
#include "pool-buffer.h"
#include "cursor-shape-v1-client-protocol.h"
#include "wlr-layer-shell-unstable-v1-client-protocol.h"
#include "xdg-output-unstable-v1-client-protocol.h"
@ -30,6 +31,7 @@ struct swaybar {
struct wl_compositor *compositor;
struct zwlr_layer_shell_v1 *layer_shell;
struct zxdg_output_manager_v1 *xdg_output_manager;
struct wp_cursor_shape_manager_v1 *cursor_shape_manager;
struct wl_shm *shm;
struct swaybar_config *config;

7
include/swaybar/image.h Normal file
View file

@ -0,0 +1,7 @@
#ifndef _SWAYBAR_IMAGE_H
#define _SWAYBAR_IMAGE_H
#include <cairo.h>
cairo_surface_t *load_image(const char *path);
#endif

View file

@ -4,6 +4,8 @@
#include <strings.h>
#include "list.h"
#include "pool-buffer.h"
#include "cursor-shape-v1-client-protocol.h"
#include "swaynag/types.h"
#define SWAYNAG_MAX_HEIGHT 500
@ -85,6 +87,7 @@ struct swaynag {
struct swaynag_output *output;
struct zwlr_layer_shell_v1 *layer_shell;
struct zwlr_layer_surface_v1 *layer_surface;
struct wp_cursor_shape_manager_v1 *cursor_shape_manager;
struct wl_surface *surface;
uint32_t width;

View file

@ -18,6 +18,7 @@ add_project_arguments(
'-Wno-unused-parameter',
'-Wno-unused-result',
'-Wno-missing-braces',
'-Wno-format-zero-length',
'-Wundef',
'-Wvla',
],
@ -36,7 +37,7 @@ if is_freebsd
endif
# Execute the wlroots subproject, if any
wlroots_version = ['>=0.17.0', '<0.18.0']
wlroots_version = ['>=0.18.0', '<0.19.0']
subproject(
'wlroots',
default_options: ['examples=false'],
@ -47,7 +48,6 @@ wlroots = dependency('wlroots', version: wlroots_version)
wlroots_features = {
'xwayland': false,
'libinput_backend': false,
'gles2_renderer': false,
'session': false,
}
foreach name, _ : wlroots_features
@ -74,7 +74,6 @@ pango = dependency('pango')
pangocairo = dependency('pangocairo')
gdk_pixbuf = dependency('gdk-pixbuf-2.0', required: get_option('gdk-pixbuf'))
pixman = dependency('pixman-1')
glesv2 = wlroots_features['gles2_renderer'] ? dependency('glesv2') : null_dep
libevdev = dependency('libevdev')
libinput = wlroots_features['libinput_backend'] ? dependency('libinput', version: '>=1.21.0') : null_dep
xcb = dependency('xcb', required: get_option('xwayland'))

View file

@ -2,7 +2,7 @@ wl_protocol_dir = wayland_protos.get_variable('pkgdatadir')
wayland_scanner_dep = dependency('wayland-scanner', native: true)
wayland_scanner = find_program(
wayland_scanner_dep.get_variable(pkgconfig: 'wayland_scanner'),
wayland_scanner_dep.get_variable('wayland_scanner'),
native: true,
)
@ -13,9 +13,9 @@ protocols = [
wl_protocol_dir / 'unstable/tablet/tablet-unstable-v2.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/cursor-shape/cursor-shape-v1.xml',
'wlr-layer-shell-unstable-v1.xml',
'idle.xml',
'wlr-input-inhibitor-unstable-v1.xml',
'wlr-output-power-management-unstable-v1.xml',
]

View file

@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<protocol name="wlr_input_inhibit_unstable_v1">
<copyright>
Copyright © 2018 Drew DeVault
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
without fee, provided that the above copyright notice appear in
all copies and that both that copyright notice and this permission
notice appear in supporting documentation, and that the name of
the copyright holders not be used in advertising or publicity
pertaining to distribution of the software without specific,
written prior permission. The copyright holders make no
representations about the suitability of this software for any
purpose. It is provided "as is" without express or implied
warranty.
THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
</copyright>
<interface name="zwlr_input_inhibit_manager_v1" version="1">
<description summary="inhibits input events to other clients">
Clients can use this interface to prevent input events from being sent to
any surfaces but its own, which is useful for example in lock screen
software. It is assumed that access to this interface will be locked down
to whitelisted clients by the compositor.
</description>
<request name="get_inhibitor">
<description summary="inhibit input to other clients">
Activates the input inhibitor. As long as the inhibitor is active, the
compositor will not send input events to other clients.
</description>
<arg name="id" type="new_id" interface="zwlr_input_inhibitor_v1"/>
</request>
<enum name="error">
<entry name="already_inhibited" value="0" summary="an input inhibitor is already in use on the compositor"/>
</enum>
</interface>
<interface name="zwlr_input_inhibitor_v1" version="1">
<description summary="inhibits input to other clients">
While this resource exists, input to clients other than the owner of the
inhibitor resource will not receive input events. The client that owns
this resource will receive all input events normally. The compositor will
also disable all of its own input processing (such as keyboard shortcuts)
while the inhibitor is active.
The compositor may continue to send input events to selected clients,
such as an on-screen keyboard (via the input-method protocol).
</description>
<request name="destroy" type="destructor">
<description summary="destroy the input inhibitor object">
Destroy the inhibitor and allow other clients to receive input.
</description>
</request>
</interface>
</protocol>

View file

@ -381,10 +381,13 @@ struct cmd_results *config_command(char *exec, char **new_block) {
sway_log(SWAY_INFO, "Config command: %s", exec);
const struct cmd_handler *handler = find_core_handler(argv[0]);
if (!handler || !handler->handle) {
const char *error = handler
? "Command '%s' is shimmed, but unimplemented"
: "Unknown/invalid command '%s'";
results = cmd_results_new(CMD_INVALID, error, argv[0]);
if (handler) {
results = cmd_results_new(CMD_INVALID,
"Command '%s' is shimmed, but unimplemented", argv[0]);
} else {
results = cmd_results_new(CMD_INVALID,
"Unknown/invalid command '%s'", argv[0]);
}
goto cleanup;
}
@ -486,20 +489,10 @@ struct cmd_results *cmd_results_new(enum cmd_status status,
}
results->status = status;
if (format) {
char *error = NULL;
va_list args;
va_start(args, format);
int slen = vsnprintf(NULL, 0, format, args);
results->error = vformat_str(format, args);
va_end(args);
if (slen > 0) {
error = malloc(slen + 1);
if (error != NULL) {
va_start(args, format);
vsnprintf(error, slen + 1, format, args);
va_end(args);
}
}
results->error = error;
} else {
results->error = NULL;
}

View file

@ -17,7 +17,7 @@ struct cmd_results *cmd_assign(int argc, char **argv) {
char *err_str = NULL;
struct criteria *criteria = criteria_parse(argv[0], &err_str);
if (!criteria) {
error = cmd_results_new(CMD_INVALID, err_str);
error = cmd_results_new(CMD_INVALID, "%s", err_str);
free(err_str);
return error;
}

View file

@ -73,12 +73,10 @@ struct cmd_results *cmd_bar(int argc, char **argv) {
}
++argv; --argc;
} else if (config->reading && !config->current_bar) {
int len = snprintf(NULL, 0, "bar-%d", config->bars->length) + 1;
id = malloc(len * sizeof(char));
id = format_str("bar-%d", config->bars->length);
if (!id) {
return cmd_results_new(CMD_FAILURE, "Unable to allocate bar id");
}
snprintf(id, len, "bar-%d", config->bars->length);
} else if (!config->reading && strcmp(argv[0], "mode") != 0 &&
strcmp(argv[0], "hidden_state") != 0) {
if (is_subcommand(argv[0])) {

View file

@ -96,7 +96,7 @@ static struct cmd_results *bar_cmd_bind(int argc, char **argv, bool code,
}
if (message) {
free_bar_binding(binding);
error = cmd_results_new(CMD_INVALID, message);
error = cmd_results_new(CMD_INVALID, "%s", message);
free(message);
return error;
} else if (!binding->button) {

View file

@ -26,7 +26,7 @@ static struct cmd_results *tray_bind(int argc, char **argv, bool code) {
}
if (message) {
free(binding);
error = cmd_results_new(CMD_INVALID, message);
error = cmd_results_new(CMD_INVALID, "%s", message);
free(message);
return error;
} else if (!binding->button) {

View file

@ -127,7 +127,7 @@ static struct cmd_results *identify_key(const char* name, bool first_key,
if (!button) {
if (message) {
struct cmd_results *error =
cmd_results_new(CMD_INVALID, message);
cmd_results_new(CMD_INVALID, "%s", message);
free(message);
return error;
} else {
@ -143,7 +143,7 @@ static struct cmd_results *identify_key(const char* name, bool first_key,
if (!button) {
if (message) {
struct cmd_results *error =
cmd_results_new(CMD_INVALID, message);
cmd_results_new(CMD_INVALID, "%s", message);
free(message);
return error;
} else {
@ -182,7 +182,7 @@ static struct cmd_results *identify_key(const char* name, bool first_key,
uint32_t button = get_mouse_bindsym(name, &message);
if (message) {
struct cmd_results *error =
cmd_results_new(CMD_INVALID, message);
cmd_results_new(CMD_INVALID, "%s", message);
free(message);
return error;
} else if (button) {
@ -539,7 +539,7 @@ struct cmd_results *cmd_bind_or_unbind_switch(int argc, char **argv,
free_switch_binding(binding);
return cmd_results_new(CMD_FAILURE,
"Invalid %s command (expected binding with the form "
"<switch>:<state>)", bindtype, argc);
"<switch>:<state>)", bindtype);
}
if (strcmp(split->items[0], "tablet") == 0) {
binding->type = WLR_SWITCH_TYPE_TABLET_MODE;
@ -549,7 +549,8 @@ struct cmd_results *cmd_bind_or_unbind_switch(int argc, char **argv,
free_switch_binding(binding);
return cmd_results_new(CMD_FAILURE,
"Invalid %s command (expected switch binding: "
"unknown switch %s)", bindtype, split->items[0]);
"unknown switch %s)", bindtype,
(const char *)split->items[0]);
}
if (strcmp(split->items[1], "on") == 0) {
binding->trigger = SWAY_SWITCH_TRIGGER_ON;
@ -562,7 +563,7 @@ struct cmd_results *cmd_bind_or_unbind_switch(int argc, char **argv,
return cmd_results_new(CMD_FAILURE,
"Invalid %s command "
"(expected switch state: unknown state %s)",
bindtype, split->items[1]);
bindtype, (const char *)split->items[1]);
}
list_free_items_and_destroy(split);

View file

@ -23,16 +23,16 @@ static struct cmd_results *handle_command(int argc, char **argv, char *cmd_name,
char *err;
int width = (int)strtol(argv[0], &err, 10);
if (*err) {
return cmd_results_new(CMD_INVALID, cmd_name, usage);
return cmd_results_new(CMD_INVALID, "%s", usage);
}
if (strcmp(argv[1], "x") != 0) {
return cmd_results_new(CMD_INVALID, cmd_name, usage);
return cmd_results_new(CMD_INVALID, "%s", usage);
}
int height = (int)strtol(argv[2], &err, 10);
if (*err) {
return cmd_results_new(CMD_INVALID, cmd_name, usage);
return cmd_results_new(CMD_INVALID, "%s", usage);
}
*config_width = width;

View file

@ -14,7 +14,7 @@ struct cmd_results *cmd_for_window(int argc, char **argv) {
char *err_str = NULL;
struct criteria *criteria = criteria_parse(argv[0], &err_str);
if (!criteria) {
error = cmd_results_new(CMD_INVALID, err_str);
error = cmd_results_new(CMD_INVALID, "%s", err_str);
free(err_str);
return error;
}

View file

@ -20,7 +20,7 @@ struct cmd_results *cmd_hide_edge_borders(int argc, char **argv) {
}
if (!argc) {
return cmd_results_new(CMD_INVALID, expected_syntax);
return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
}
if (strcmp(argv[0], "none") == 0) {
@ -38,7 +38,7 @@ struct cmd_results *cmd_hide_edge_borders(int argc, char **argv) {
config->hide_edge_borders = E_NONE;
config->hide_edge_borders_smart = ESMART_NO_GAPS;
} else {
return cmd_results_new(CMD_INVALID, expected_syntax);
return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
}
config->hide_lone_tab = hide_lone_tab;

View file

@ -41,7 +41,7 @@ struct cmd_results *cmd_inhibit_idle(int argc, char **argv) {
sway_idle_inhibit_v1_user_inhibitor_destroy(inhibitor);
} else {
inhibitor->mode = mode;
sway_idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1);
sway_idle_inhibit_v1_check_active();
}
} else if (!clear) {
sway_idle_inhibit_v1_user_inhibitor_register(con->view, mode);

View file

@ -27,6 +27,7 @@ static const struct cmd_handler input_handlers[] = {
{ "repeat_rate", input_cmd_repeat_rate },
{ "rotation_angle", input_cmd_rotation_angle },
{ "scroll_button", input_cmd_scroll_button },
{ "scroll_button_lock", input_cmd_scroll_button_lock },
{ "scroll_factor", input_cmd_scroll_factor },
{ "scroll_method", input_cmd_scroll_method },
{ "tap", input_cmd_tap },

View file

@ -11,11 +11,21 @@ static bool parse_coords(const char *str, double *x, double *y, bool *mm) {
*mm = false;
char *end;
*x = strtod(str, &end);
if (end[0] != 'x') {
return false;
// Check for "0x" prefix to avoid strtod treating the string as hex
if (str[0] == '0' && str[1] == 'x') {
if (strlen(str) < 3) {
return false;
}
*x = 0;
end = (char *)str + 2;
} else {
*x = strtod(str, &end);
if (end[0] != 'x') {
return false;
}
++end;
}
++end;
*y = strtod(end, &end);
if (end[0] == 'm') {

View file

@ -49,5 +49,5 @@ struct cmd_results *input_cmd_map_to_region(int argc, char **argv) {
error:
free(ic->mapped_to_region);
ic->mapped_to_region = NULL;
return cmd_results_new(CMD_FAILURE, errstr);
return cmd_results_new(CMD_FAILURE, "%s", errstr);
}

View file

@ -21,7 +21,7 @@ struct cmd_results *input_cmd_scroll_button(int argc, char **argv) {
char *message = NULL;
uint32_t button = get_mouse_button(*argv, &message);
if (message) {
error = cmd_results_new(CMD_INVALID, message);
error = cmd_results_new(CMD_INVALID, "%s", message);
free(message);
return error;
} else if (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_DOWN

View file

@ -0,0 +1,26 @@
#include <libinput.h>
#include <string.h>
#include <strings.h>
#include "sway/config.h"
#include "sway/commands.h"
#include "sway/input/input-manager.h"
#include "util.h"
struct cmd_results *input_cmd_scroll_button_lock(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "scroll_button_lock", EXPECTED_AT_LEAST, 1))) {
return error;
}
struct input_config *ic = config->handler_context.input_config;
if (!ic) {
return cmd_results_new(CMD_FAILURE, "No input device defined.");
}
if (parse_boolean(argv[0], true)) {
ic->scroll_button_lock = LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_ENABLED;
} else {
ic->scroll_button_lock = LIBINPUT_CONFIG_SCROLL_BUTTON_LOCK_DISABLED;
}
return cmd_results_new(CMD_SUCCESS, NULL);
}

View file

@ -153,7 +153,7 @@ struct cmd_results *cmd_layout(int argc, char **argv) {
workspace->output);
}
if (new_layout == L_NONE) {
return cmd_results_new(CMD_INVALID, expected_syntax);
return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
}
if (new_layout != old_layout) {
if (container) {

View file

@ -470,7 +470,7 @@ static struct cmd_results *cmd_move_container(bool no_auto_back_and_forth,
if (strcasecmp(argv[1], "number") == 0) {
// move [window|container] [to] "workspace number x"
if (argc < 3) {
return cmd_results_new(CMD_INVALID, expected_syntax);
return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
}
if (!isdigit(argv[2][0])) {
return cmd_results_new(CMD_INVALID,
@ -530,7 +530,7 @@ static struct cmd_results *cmd_move_container(bool no_auto_back_and_forth,
}
destination = &dest_con->node;
} else {
return cmd_results_new(CMD_INVALID, expected_syntax);
return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
}
if (destination->type == N_CONTAINER &&
@ -829,7 +829,7 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) {
}
if (!argc) {
return cmd_results_new(CMD_INVALID, expected_position_syntax);
return cmd_results_new(CMD_INVALID, "%s", expected_position_syntax);
}
bool absolute = false;
@ -839,19 +839,19 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) {
++argv;
}
if (!argc) {
return cmd_results_new(CMD_INVALID, expected_position_syntax);
return cmd_results_new(CMD_INVALID, "%s", expected_position_syntax);
}
if (strcmp(argv[0], "position") == 0) {
--argc;
++argv;
}
if (!argc) {
return cmd_results_new(CMD_INVALID, expected_position_syntax);
return cmd_results_new(CMD_INVALID, "%s", expected_position_syntax);
}
if (strcmp(argv[0], "cursor") == 0 || strcmp(argv[0], "mouse") == 0 ||
strcmp(argv[0], "pointer") == 0) {
if (absolute) {
return cmd_results_new(CMD_INVALID, expected_position_syntax);
return cmd_results_new(CMD_INVALID, "%s", expected_position_syntax);
}
return cmd_move_to_position_pointer(container);
} else if (strcmp(argv[0], "center") == 0) {
@ -873,7 +873,7 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) {
}
if (argc < 2) {
return cmd_results_new(CMD_FAILURE, expected_position_syntax);
return cmd_results_new(CMD_FAILURE, "%s", expected_position_syntax);
}
struct movement_amount lx = { .amount = 0, .unit = MOVEMENT_UNIT_INVALID };
@ -886,7 +886,7 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) {
}
if (argc < 1) {
return cmd_results_new(CMD_FAILURE, expected_position_syntax);
return cmd_results_new(CMD_FAILURE, "%s", expected_position_syntax);
}
struct movement_amount ly = { .amount = 0, .unit = MOVEMENT_UNIT_INVALID };
@ -895,7 +895,7 @@ static struct cmd_results *cmd_move_to_position(int argc, char **argv) {
argc -= num_consumed_args;
argv += num_consumed_args;
if (argc > 0) {
return cmd_results_new(CMD_INVALID, expected_position_syntax);
return cmd_results_new(CMD_INVALID, "%s", expected_position_syntax);
}
if (ly.unit == MOVEMENT_UNIT_INVALID) {
return cmd_results_new(CMD_INVALID, "Invalid y position specified");
@ -1041,13 +1041,13 @@ struct cmd_results *cmd_move(int argc, char **argv) {
}
if (!argc) {
return cmd_results_new(CMD_INVALID, expected_full_syntax);
return cmd_results_new(CMD_INVALID, "%s", expected_full_syntax);
}
// Only `move [window|container] [to] workspace` supports
// `--no-auto-back-and-forth` so treat others as invalid syntax
if (no_auto_back_and_forth && strcasecmp(argv[0], "workspace") != 0) {
return cmd_results_new(CMD_INVALID, expected_full_syntax);
return cmd_results_new(CMD_INVALID, "%s", expected_full_syntax);
}
if (strcasecmp(argv[0], "workspace") == 0 ||
@ -1061,5 +1061,5 @@ struct cmd_results *cmd_move(int argc, char **argv) {
strcasecmp(argv[1], "position") == 0)) {
return cmd_move_to_position(argc, argv);
}
return cmd_results_new(CMD_INVALID, expected_full_syntax);
return cmd_results_new(CMD_INVALID, "%s", expected_full_syntax);
}

View file

@ -13,7 +13,7 @@ struct cmd_results *cmd_no_focus(int argc, char **argv) {
char *err_str = NULL;
struct criteria *criteria = criteria_parse(argv[0], &err_str);
if (!criteria) {
error = cmd_results_new(CMD_INVALID, err_str);
error = cmd_results_new(CMD_INVALID, "%s", err_str);
free(err_str);
return error;
}

View file

@ -1,4 +1,5 @@
#include <string.h>
#include <wlr/util/transform.h>
#include "sway/commands.h"
#include "sway/config.h"
#include "log.h"

View file

@ -26,7 +26,7 @@ struct cmd_results *cmd_rename(int argc, char **argv) {
"Can't run this command while there's no outputs connected.");
}
if (strcasecmp(argv[0], "workspace") != 0) {
return cmd_results_new(CMD_INVALID, expected_syntax);
return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
}
int argn = 1;
@ -65,7 +65,7 @@ struct cmd_results *cmd_rename(int argc, char **argv) {
++argn; // move past "to"
if (argn >= argc) {
return cmd_results_new(CMD_INVALID, expected_syntax);
return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
}
char *new_name = join_args(argv + argn, argc - argn);

View file

@ -75,6 +75,10 @@ void container_resize_tiled(struct sway_container *con,
return;
}
if (container_is_scratchpad_hidden_or_child(con)) {
return;
}
// For HORIZONTAL or VERTICAL, we are growing in two directions so select
// both adjacent siblings. For RIGHT or DOWN, just select the next sibling.
// For LEFT or UP, convert it to a RIGHT or DOWN resize and reassign con to
@ -249,16 +253,35 @@ static struct cmd_results *resize_adjust_tiled(uint32_t axis,
struct movement_amount *amount) {
struct sway_container *current = config->handler_context.container;
if (container_is_scratchpad_hidden_or_child(current)) {
return cmd_results_new(CMD_FAILURE, "Cannot resize a hidden scratchpad container");
}
if (amount->unit == MOVEMENT_UNIT_DEFAULT) {
amount->unit = MOVEMENT_UNIT_PPT;
}
if (amount->unit == MOVEMENT_UNIT_PPT) {
struct sway_container *parent = current->pending.parent;
float pct = amount->amount / 100.0f;
if (is_horizontal(axis)) {
amount->amount = (float)current->pending.width * pct;
while (parent && parent->pending.layout != L_HORIZ) {
parent = parent->pending.parent;
}
if (parent) {
amount->amount = (float)parent->pending.width * pct;
} else {
amount->amount = (float)current->pending.workspace->width * pct;
}
} else {
amount->amount = (float)current->pending.height * pct;
while (parent && parent->pending.layout != L_VERT) {
parent = parent->pending.parent;
}
if (parent) {
amount->amount = (float)parent->pending.height * pct;
} else {
amount->amount = (float)current->pending.workspace->height * pct;
}
}
}
@ -277,6 +300,11 @@ static struct cmd_results *resize_adjust_tiled(uint32_t axis,
*/
static struct cmd_results *resize_set_tiled(struct sway_container *con,
struct movement_amount *width, struct movement_amount *height) {
if (container_is_scratchpad_hidden_or_child(con)) {
return cmd_results_new(CMD_FAILURE, "Cannot resize a hidden scratchpad container");
}
if (width->amount) {
if (width->unit == MOVEMENT_UNIT_PPT ||
width->unit == MOVEMENT_UNIT_DEFAULT) {
@ -415,7 +443,7 @@ static struct cmd_results *cmd_resize_set(int argc, char **argv) {
argc -= num_consumed_args;
argv += num_consumed_args;
if (width.unit == MOVEMENT_UNIT_INVALID) {
return cmd_results_new(CMD_INVALID, usage);
return cmd_results_new(CMD_INVALID, "%s", usage);
}
}
@ -427,10 +455,10 @@ static struct cmd_results *cmd_resize_set(int argc, char **argv) {
}
int num_consumed_args = parse_movement_amount(argc, argv, &height);
if (argc > num_consumed_args) {
return cmd_results_new(CMD_INVALID, usage);
return cmd_results_new(CMD_INVALID, "%s", usage);
}
if (width.unit == MOVEMENT_UNIT_INVALID) {
return cmd_results_new(CMD_INVALID, usage);
return cmd_results_new(CMD_INVALID, "%s", usage);
}
}
@ -462,7 +490,7 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv,
"[<amount> px|ppt [or <amount> px|ppt]]'";
uint32_t axis = parse_resize_axis(*argv);
if (axis == WLR_EDGE_NONE) {
return cmd_results_new(CMD_INVALID, usage);
return cmd_results_new(CMD_INVALID, "%s", usage);
}
--argc; ++argv;
@ -473,7 +501,7 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv,
argc -= num_consumed_args;
argv += num_consumed_args;
if (first_amount.unit == MOVEMENT_UNIT_INVALID) {
return cmd_results_new(CMD_INVALID, usage);
return cmd_results_new(CMD_INVALID, "%s", usage);
}
} else {
first_amount.amount = 10;
@ -483,7 +511,7 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv,
// "or"
if (argc) {
if (strcmp(*argv, "or") != 0) {
return cmd_results_new(CMD_INVALID, usage);
return cmd_results_new(CMD_INVALID, "%s", usage);
}
--argc; ++argv;
}
@ -493,10 +521,10 @@ static struct cmd_results *cmd_resize_adjust(int argc, char **argv,
if (argc) {
int num_consumed_args = parse_movement_amount(argc, argv, &second_amount);
if (argc > num_consumed_args) {
return cmd_results_new(CMD_INVALID, usage);
return cmd_results_new(CMD_INVALID, "%s", usage);
}
if (second_amount.unit == MOVEMENT_UNIT_INVALID) {
return cmd_results_new(CMD_INVALID, usage);
return cmd_results_new(CMD_INVALID, "%s", usage);
}
} else {
second_amount.amount = 0;
@ -566,5 +594,5 @@ struct cmd_results *cmd_resize(int argc, char **argv) {
const char usage[] = "Expected 'resize <shrink|grow> "
"<width|height|up|down|left|right> [<amount>] [px|ppt]'";
return cmd_results_new(CMD_INVALID, usage);
return cmd_results_new(CMD_INVALID, "%s", usage);
}

View file

@ -18,7 +18,7 @@ static struct cmd_results *handle_command(struct sway_cursor *cursor,
int argc, char **argv) {
if (strcasecmp(argv[0], "move") == 0) {
if (argc < 3) {
return cmd_results_new(CMD_INVALID, expected_syntax);
return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
}
int delta_x = strtol(argv[1], NULL, 10);
int delta_y = strtol(argv[2], NULL, 10);
@ -27,7 +27,7 @@ static struct cmd_results *handle_command(struct sway_cursor *cursor,
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
} else if (strcasecmp(argv[0], "set") == 0) {
if (argc < 3) {
return cmd_results_new(CMD_INVALID, expected_syntax);
return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
}
// map absolute coords (0..1,0..1) to root container coords
float x = strtof(argv[1], NULL) / root->width;
@ -37,7 +37,7 @@ static struct cmd_results *handle_command(struct sway_cursor *cursor,
wlr_seat_pointer_notify_frame(cursor->seat->wlr_seat);
} else {
if (argc < 2) {
return cmd_results_new(CMD_INVALID, expected_syntax);
return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
}
struct cmd_results *error = NULL;
if ((error = press_or_release(cursor, argv[0], argv[1]))) {
@ -92,14 +92,14 @@ static struct cmd_results *press_or_release(struct sway_cursor *cursor,
} else if (strcasecmp(action, "release") == 0) {
state = WLR_BUTTON_RELEASED;
} else {
return cmd_results_new(CMD_INVALID, expected_syntax);
return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
}
char *message = NULL;
button = get_mouse_button(button_str, &message);
if (message) {
struct cmd_results *error =
cmd_results_new(CMD_INVALID, message);
cmd_results_new(CMD_INVALID, "%s", message);
free(message);
return error;
} else if (button == SWAY_SCROLL_UP || button == SWAY_SCROLL_DOWN

View file

@ -3,6 +3,7 @@
#include <string.h>
#include <strings.h>
#include <stdint.h>
#include "log.h"
#include "sway/commands.h"
#include "sway/config.h"
#include "sway/input/seat.h"
@ -69,5 +70,10 @@ struct cmd_results *seat_cmd_idle_wake(int argc, char **argv) {
return cmd_results_new(CMD_FAILURE, "Invalid idle source");
}
config->handler_context.seat_config->idle_wake_sources = sources;
sway_log(SWAY_INFO, "Warning: seat idle_wake is deprecated");
if (config->reading) {
config_add_swaynag_warning("seat idle_wake is deprecated. "
"Only seat idle_inhibit is supported.");
}
return cmd_results_new(CMD_SUCCESS, NULL);
}

View file

@ -32,7 +32,7 @@ static struct cmd_results *do_split(int layout) {
return cmd_results_new(CMD_SUCCESS, NULL);
}
static struct cmd_results *do_unsplit() {
static struct cmd_results *do_unsplit(void) {
struct sway_container *con = config->handler_context.container;
struct sway_workspace *ws = config->handler_context.workspace;

View file

@ -46,7 +46,7 @@ struct cmd_results *cmd_swap(int argc, char **argv) {
}
if (strcasecmp(argv[0], "container") || strcasecmp(argv[1], "with")) {
return cmd_results_new(CMD_INVALID, expected_syntax);
return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
}
struct sway_container *current = config->handler_context.container;
@ -65,7 +65,7 @@ struct cmd_results *cmd_swap(int argc, char **argv) {
other = root_find_container(test_mark, value);
} else {
free(value);
return cmd_results_new(CMD_INVALID, expected_syntax);
return cmd_results_new(CMD_INVALID, "%s", expected_syntax);
}
if (!other) {

View file

@ -61,7 +61,7 @@ static struct cmd_results *cmd_workspace_gaps(int argc, char **argv,
const char expected[] = "Expected 'workspace <name> gaps "
"inner|outer|horizontal|vertical|top|right|bottom|left <px>'";
if (gaps_location == 0) {
return cmd_results_new(CMD_INVALID, expected);
return cmd_results_new(CMD_INVALID, "%s", expected);
}
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "workspace", EXPECTED_EQUAL_TO,
@ -79,7 +79,7 @@ static struct cmd_results *cmd_workspace_gaps(int argc, char **argv,
char *end;
int amount = strtol(argv[gaps_location + 2], &end, 10);
if (strlen(end)) {
return cmd_results_new(CMD_FAILURE, expected);
return cmd_results_new(CMD_FAILURE, "%s", expected);
}
bool valid = false;
@ -110,7 +110,7 @@ static struct cmd_results *cmd_workspace_gaps(int argc, char **argv,
}
}
if (!valid) {
return cmd_results_new(CMD_INVALID, expected);
return cmd_results_new(CMD_INVALID, "%s", expected);
}
// Prevent invalid gaps configurations.
@ -174,7 +174,7 @@ struct cmd_results *cmd_workspace(int argc, char **argv) {
}
if (root->fullscreen_global) {
return cmd_results_new(CMD_FAILURE, "workspace",
return cmd_results_new(CMD_FAILURE,
"Can't switch workspaces while fullscreen global");
}

View file

@ -924,23 +924,18 @@ void config_add_swaynag_warning(char *fmt, ...) {
if (config->reading && !config->validating) {
va_list args;
va_start(args, fmt);
size_t length = vsnprintf(NULL, 0, fmt, args) + 1;
char *str = vformat_str(fmt, args);
va_end(args);
char *temp = malloc(length + 1);
if (!temp) {
sway_log(SWAY_ERROR, "Failed to allocate buffer for warning.");
if (str == NULL) {
return;
}
va_start(args, fmt);
vsnprintf(temp, length, fmt, args);
va_end(args);
swaynag_log(config->swaynag_command, &config->swaynag_config_errors,
"Warning on line %i (%s) '%s': %s",
config->current_config_line_number, config->current_config_path,
config->current_config_line, temp);
config->current_config_line, str);
free(str);
}
}

View file

@ -35,6 +35,7 @@ struct input_config *new_input_config(const char* identifier) {
input->pointer_accel = FLT_MIN;
input->scroll_factor = FLT_MIN;
input->scroll_button = INT_MIN;
input->scroll_button_lock = INT_MIN;
input->scroll_method = INT_MIN;
input->left_handed = INT_MIN;
input->repeat_delay = INT_MIN;
@ -96,6 +97,9 @@ void merge_input_config(struct input_config *dst, struct input_config *src) {
if (src->scroll_button != INT_MIN) {
dst->scroll_button = src->scroll_button;
}
if (src->scroll_button_lock != INT_MIN) {
dst->scroll_button_lock = src->scroll_button_lock;
}
if (src->send_events != INT_MIN) {
dst->send_events = src->send_events;
}

View file

@ -153,25 +153,16 @@ static void merge_wildcard_on_all(struct output_config *wildcard) {
}
static void merge_id_on_name(struct output_config *oc) {
char *id_on_name = NULL;
char id[128];
char *name = NULL;
struct sway_output *output;
wl_list_for_each(output, &root->all_outputs, link) {
name = output->wlr_output->name;
output_get_identifier(id, sizeof(id), output);
if (strcmp(name, oc->name) == 0 || strcmp(id, oc->name) == 0) {
size_t length = snprintf(NULL, 0, "%s on %s", id, name) + 1;
id_on_name = malloc(length);
if (!id_on_name) {
sway_log(SWAY_ERROR, "Failed to allocate id on name string");
return;
}
snprintf(id_on_name, length, "%s on %s", id, name);
break;
}
struct sway_output *output = all_output_by_name_or_id(oc->name);
if (output == NULL) {
return;
}
const char *name = output->wlr_output->name;
char id[128];
output_get_identifier(id, sizeof(id), output);
char *id_on_name = format_str("%s on %s", id, name);
if (!id_on_name) {
return;
}
@ -258,6 +249,8 @@ static void set_mode(struct wlr_output *output, struct wlr_output_state *pending
// as (int)(1000 * mHz / 1000.f)
// round() the result to avoid any error
int mhz = (int)roundf(refresh_rate * 1000);
// If no target refresh rate is given, match highest available
mhz = mhz <= 0 ? INT_MAX : mhz;
if (wl_list_empty(&output->modes) || custom) {
sway_log(SWAY_DEBUG, "Assigning custom mode to %s", output->name);
@ -267,23 +260,28 @@ static void set_mode(struct wlr_output *output, struct wlr_output_state *pending
}
struct wlr_output_mode *mode, *best = NULL;
int best_diff_mhz = INT_MAX;
wl_list_for_each(mode, &output->modes, link) {
if (mode->width == width && mode->height == height) {
if (mode->refresh == mhz) {
best = mode;
break;
}
if (best == NULL || mode->refresh > best->refresh) {
int diff_mhz = abs(mode->refresh - mhz);
if (diff_mhz < best_diff_mhz) {
best_diff_mhz = diff_mhz;
best = mode;
if (best_diff_mhz == 0) {
break;
}
}
}
}
if (!best) {
sway_log(SWAY_ERROR, "Configured mode for %s not available", output->name);
sway_log(SWAY_INFO, "Picking preferred mode instead");
best = wlr_output_preferred_mode(output);
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 {
sway_log(SWAY_DEBUG, "Assigning configured mode to %s", output->name);
best = wlr_output_preferred_mode(output);
sway_log(SWAY_INFO, "Configured mode (%dx%d@%.3fHz) not available, "
"applying preferred mode (%dx%d@%.3fHz)",
width, height, refresh_rate,
best->width, best->height, best->refresh / 1000.f);
}
wlr_output_state_set_mode(pending, best);
}
@ -519,10 +517,6 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
struct wlr_output_state pending = {0};
queue_output_config(oc, output, &pending);
if (!oc || oc->power != 0) {
output->current_mode = pending.mode;
}
sway_log(SWAY_DEBUG, "Committing output %s", wlr_output->name);
if (!wlr_output_commit_state(wlr_output, &pending)) {
// Failed to commit output changes, maybe the output is missing a CRTC.
@ -596,7 +590,7 @@ bool apply_output_config(struct output_config *oc, struct sway_output *output) {
// Reconfigure all devices, since input config may have been applied before
// this output came online, and some config items (like map_to_output) are
// dependent on an output being present.
input_manager_configure_all_inputs();
input_manager_configure_all_input_mappings();
// Reconfigure the cursor images, since the scale may have changed.
input_manager_configure_xcursor();
return true;
@ -639,9 +633,7 @@ static struct output_config *get_output_config(char *identifier,
struct output_config *oc_name = NULL;
struct output_config *oc_id = NULL;
size_t length = snprintf(NULL, 0, "%s on %s", identifier, name) + 1;
char *id_on_name = malloc(length);
snprintf(id_on_name, length, "%s on %s", identifier, name);
char *id_on_name = format_str("%s on %s", identifier, name);
int i = list_seq_find(config->output_configs, output_name_cmp, id_on_name);
if (i >= 0) {
oc_id_on_name = config->output_configs->items[i];
@ -728,12 +720,11 @@ void apply_output_config_to_outputs(struct output_config *oc) {
// this is during startup then there will be no container and config
// will be applied during normal "new output" event from wlroots.
bool wildcard = strcmp(oc->name, "*") == 0;
char id[128];
struct sway_output *sway_output, *tmp;
wl_list_for_each_safe(sway_output, tmp, &root->all_outputs, link) {
char *name = sway_output->wlr_output->name;
output_get_identifier(id, sizeof(id), sway_output);
if (wildcard || !strcmp(name, oc->name) || !strcmp(id, oc->name)) {
if (output_match_name_or_id(sway_output, oc->name)) {
char id[128];
output_get_identifier(id, sizeof(id), sway_output);
struct output_config *current = get_output_config(id, sway_output);
if (!current) {
// No stored output config matched, apply oc directly

View file

@ -19,6 +19,7 @@
bool criteria_is_empty(struct criteria *criteria) {
return !criteria->title
&& !criteria->shell
&& !criteria->all
&& !criteria->app_id
&& !criteria->con_mark
&& !criteria->con_id
@ -456,6 +457,7 @@ static enum atom_name parse_window_type(const char *type) {
#endif
enum criteria_token {
T_ALL,
T_APP_ID,
T_CON_ID,
T_CON_MARK,
@ -478,7 +480,9 @@ enum criteria_token {
};
static enum criteria_token token_from_name(char *name) {
if (strcmp(name, "app_id") == 0) {
if (strcmp(name, "all") == 0) {
return T_ALL;
} else if (strcmp(name, "app_id") == 0) {
return T_APP_ID;
} else if (strcmp(name, "con_id") == 0) {
return T_CON_ID;
@ -524,8 +528,8 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
return false;
}
// Require value, unless token is floating or tiled
if (!value && token != T_FLOATING && token != T_TILING) {
// Require value, unless token is all, floating or tiled
if (!value && token != T_ALL && token != T_FLOATING && token != T_TILING) {
const char *fmt = "Token '%s' requires a value";
int len = strlen(fmt) + strlen(name) - 1;
error = malloc(len);
@ -535,6 +539,9 @@ static bool parse_token(struct criteria *criteria, char *name, char *value) {
char *endptr = NULL;
switch (token) {
case T_ALL:
criteria->all = true;
break;
case T_TITLE:
pattern_create(&criteria->title, value);
break;

View file

@ -1,5 +1,4 @@
#include <stdlib.h>
#include <wlr/types/wlr_idle.h>
#include <wlr/types/wlr_idle_notify_v1.h>
#include "log.h"
#include "sway/desktop/idle_inhibit_v1.h"
@ -12,7 +11,7 @@
static void destroy_inhibitor(struct sway_idle_inhibitor_v1 *inhibitor) {
wl_list_remove(&inhibitor->link);
wl_list_remove(&inhibitor->destroy.link);
sway_idle_inhibit_v1_check_active(inhibitor->manager);
sway_idle_inhibit_v1_check_active();
free(inhibitor);
}
@ -35,7 +34,6 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) {
return;
}
inhibitor->manager = manager;
inhibitor->mode = INHIBIT_IDLE_APPLICATION;
inhibitor->wlr_inhibitor = wlr_inhibitor;
wl_list_insert(&manager->inhibitors, &inhibitor->link);
@ -43,33 +41,34 @@ void handle_idle_inhibitor_v1(struct wl_listener *listener, void *data) {
inhibitor->destroy.notify = handle_destroy;
wl_signal_add(&wlr_inhibitor->events.destroy, &inhibitor->destroy);
sway_idle_inhibit_v1_check_active(manager);
sway_idle_inhibit_v1_check_active();
}
void sway_idle_inhibit_v1_user_inhibitor_register(struct sway_view *view,
enum sway_idle_inhibit_mode mode) {
struct sway_idle_inhibit_manager_v1 *manager = &server.idle_inhibit_manager_v1;
struct sway_idle_inhibitor_v1 *inhibitor =
calloc(1, sizeof(struct sway_idle_inhibitor_v1));
if (!inhibitor) {
return;
}
inhibitor->manager = server.idle_inhibit_manager_v1;
inhibitor->mode = mode;
inhibitor->view = view;
wl_list_insert(&inhibitor->manager->inhibitors, &inhibitor->link);
wl_list_insert(&manager->inhibitors, &inhibitor->link);
inhibitor->destroy.notify = handle_destroy;
wl_signal_add(&view->events.unmap, &inhibitor->destroy);
sway_idle_inhibit_v1_check_active(inhibitor->manager);
sway_idle_inhibit_v1_check_active();
}
struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_user_inhibitor_for_view(
struct sway_view *view) {
struct sway_idle_inhibit_manager_v1 *manager = &server.idle_inhibit_manager_v1;
struct sway_idle_inhibitor_v1 *inhibitor;
wl_list_for_each(inhibitor, &server.idle_inhibit_manager_v1->inhibitors,
link) {
wl_list_for_each(inhibitor, &manager->inhibitors, link) {
if (inhibitor->mode != INHIBIT_IDLE_APPLICATION &&
inhibitor->view == view) {
return inhibitor;
@ -80,9 +79,9 @@ struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_user_inhibitor_for_view(
struct sway_idle_inhibitor_v1 *sway_idle_inhibit_v1_application_inhibitor_for_view(
struct sway_view *view) {
struct sway_idle_inhibit_manager_v1 *manager = &server.idle_inhibit_manager_v1;
struct sway_idle_inhibitor_v1 *inhibitor;
wl_list_for_each(inhibitor, &server.idle_inhibit_manager_v1->inhibitors,
link) {
wl_list_for_each(inhibitor, &manager->inhibitors, link) {
if (inhibitor->mode == INHIBIT_IDLE_APPLICATION &&
view_from_wlr_surface(inhibitor->wlr_inhibitor->surface) == view) {
return inhibitor;
@ -131,8 +130,8 @@ bool sway_idle_inhibit_v1_is_active(struct sway_idle_inhibitor_v1 *inhibitor) {
return false;
}
void sway_idle_inhibit_v1_check_active(
struct sway_idle_inhibit_manager_v1 *manager) {
void sway_idle_inhibit_v1_check_active(void) {
struct sway_idle_inhibit_manager_v1 *manager = &server.idle_inhibit_manager_v1;
struct sway_idle_inhibitor_v1 *inhibitor;
bool inhibited = false;
wl_list_for_each(inhibitor, &manager->inhibitors, link) {
@ -140,28 +139,21 @@ void sway_idle_inhibit_v1_check_active(
break;
}
}
wlr_idle_set_enabled(manager->idle, NULL, !inhibited);
wlr_idle_notifier_v1_set_inhibited(server.idle_notifier_v1, inhibited);
}
struct sway_idle_inhibit_manager_v1 *sway_idle_inhibit_manager_v1_create(
struct wl_display *wl_display, struct wlr_idle *idle) {
struct sway_idle_inhibit_manager_v1 *manager =
calloc(1, sizeof(struct sway_idle_inhibit_manager_v1));
if (!manager) {
return NULL;
bool sway_idle_inhibit_manager_v1_init(void) {
struct sway_idle_inhibit_manager_v1 *manager = &server.idle_inhibit_manager_v1;
manager->wlr_manager = wlr_idle_inhibit_v1_create(server.wl_display);
if (!manager->wlr_manager) {
return false;
}
manager->wlr_manager = wlr_idle_inhibit_v1_create(wl_display);
if (!manager->wlr_manager) {
free(manager);
return NULL;
}
manager->idle = idle;
wl_signal_add(&manager->wlr_manager->events.new_inhibitor,
&manager->new_idle_inhibitor_v1);
manager->new_idle_inhibitor_v1.notify = handle_idle_inhibitor_v1;
wl_list_init(&manager->inhibitors);
return manager;
return true;
}

View file

@ -228,7 +228,7 @@ struct launcher_ctx *launcher_ctx_create(struct wlr_xdg_activation_token_v1 *tok
}
// Creates a context with a new token for the internal launcher
struct launcher_ctx *launcher_ctx_create_internal() {
struct launcher_ctx *launcher_ctx_create_internal(void) {
struct sway_seat *seat = input_manager_current_seat();
struct sway_workspace *ws = seat_get_focused_workspace(seat);
if (!ws) {

View file

@ -17,6 +17,39 @@
#include "sway/tree/arrange.h"
#include "sway/tree/workspace.h"
struct wlr_layer_surface_v1 *toplevel_layer_surface_from_surface(
struct wlr_surface *surface) {
struct wlr_layer_surface_v1 *layer;
do {
if (!surface) {
return NULL;
}
// Topmost layer surface
if ((layer = wlr_layer_surface_v1_try_from_wlr_surface(surface))) {
return layer;
}
// Layer subsurface
if (wlr_subsurface_try_from_wlr_surface(surface)) {
surface = wlr_surface_get_root_surface(surface);
continue;
}
// Layer surface popup
struct wlr_xdg_surface *xdg_surface = NULL;
if ((xdg_surface = wlr_xdg_surface_try_from_wlr_surface(surface)) &&
xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP && xdg_surface->popup != NULL) {
if (!xdg_surface->popup->parent) {
return NULL;
}
surface = wlr_surface_get_root_surface(xdg_surface->popup->parent);
continue;
}
// Return early if the surface is not a layer/xdg_popup/sub surface
return NULL;
} while (true);
}
static void apply_exclusive(struct wlr_box *usable_area,
uint32_t anchor, int32_t exclusive,
int32_t margin_top, int32_t margin_right,
@ -218,8 +251,9 @@ void arrange_layers(struct sway_output *output) {
for (size_t i = 0; i < nlayers; ++i) {
wl_list_for_each_reverse(layer,
&output->layers[layers_above_shell[i]], link) {
if (layer->layer_surface->current.keyboard_interactive &&
layer->layer_surface->mapped) {
if (layer->layer_surface->current.keyboard_interactive
== ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE &&
layer->layer_surface->surface->mapped) {
topmost = layer;
break;
}
@ -231,10 +265,12 @@ void arrange_layers(struct sway_output *output) {
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) {
seat->focused_layer->current.keyboard_interactive
!= ZWLR_LAYER_SURFACE_V1_KEYBOARD_INTERACTIVITY_EXCLUSIVE) {
seat_set_focus_layer(seat, NULL);
}
}
@ -253,7 +289,7 @@ static struct sway_layer_surface *find_mapped_layer_by_client(
&output->layers[ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY], link) {
struct wl_resource *resource = lsurface->layer_surface->resource;
if (wl_resource_get_client(resource) == client
&& lsurface->layer_surface->mapped) {
&& lsurface->layer_surface->surface->mapped) {
return lsurface;
}
}
@ -293,8 +329,8 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {
bool layer_changed = false;
if (layer_surface->current.committed != 0
|| layer->mapped != layer_surface->mapped) {
layer->mapped = layer_surface->mapped;
|| layer->mapped != layer_surface->surface->mapped) {
layer->mapped = layer_surface->surface->mapped;
layer_changed = layer->layer != layer_surface->current.layer;
if (layer_changed) {
wl_list_remove(&layer->link);
@ -312,6 +348,8 @@ static void handle_surface_commit(struct wl_listener *listener, void *data) {
bool extent_changed =
memcmp(&old_extent, &layer->extent, sizeof(struct wlr_box)) != 0;
if (extent_changed || layer_changed) {
old_extent.x += output->lx;
old_extent.y += output->ly;
output_damage_box(output, &old_extent);
output_damage_surface(output, layer->geo.x, layer->geo.y,
layer_surface->surface, true);
@ -347,7 +385,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
wl_container_of(listener, sway_layer, destroy);
sway_log(SWAY_DEBUG, "Layer surface destroyed (%s)",
sway_layer->layer_surface->namespace);
if (sway_layer->layer_surface->mapped) {
if (sway_layer->layer_surface->surface->mapped) {
unmap(sway_layer);
}
@ -452,9 +490,9 @@ static struct sway_layer_subsurface *create_subsurface(
wl_list_insert(&layer_surface->subsurfaces, &subsurface->link);
subsurface->map.notify = subsurface_handle_map;
wl_signal_add(&wlr_subsurface->events.map, &subsurface->map);
wl_signal_add(&wlr_subsurface->surface->events.map, &subsurface->map);
subsurface->unmap.notify = subsurface_handle_unmap;
wl_signal_add(&wlr_subsurface->events.unmap, &subsurface->unmap);
wl_signal_add(&wlr_subsurface->surface->events.unmap, &subsurface->unmap);
subsurface->destroy.notify = subsurface_handle_destroy;
wl_signal_add(&wlr_subsurface->events.destroy, &subsurface->destroy);
subsurface->commit.notify = subsurface_handle_commit;
@ -504,36 +542,6 @@ static void popup_damage(struct sway_layer_popup *layer_popup, bool whole) {
output_damage_surface(output, ox, oy, surface, whole);
}
static void popup_handle_map(struct wl_listener *listener, void *data) {
struct sway_layer_popup *popup = wl_container_of(listener, popup, map);
struct sway_layer_surface *layer = popup_get_layer(popup);
struct wlr_output *wlr_output = layer->layer_surface->output;
sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
surface_enter_output(popup->wlr_popup->base->surface, wlr_output->data);
popup_damage(popup, true);
}
static void popup_handle_unmap(struct wl_listener *listener, void *data) {
struct sway_layer_popup *popup = wl_container_of(listener, popup, unmap);
popup_damage(popup, true);
}
static void popup_handle_commit(struct wl_listener *listener, void *data) {
struct sway_layer_popup *popup = wl_container_of(listener, popup, commit);
popup_damage(popup, false);
}
static void popup_handle_destroy(struct wl_listener *listener, void *data) {
struct sway_layer_popup *popup =
wl_container_of(listener, popup, destroy);
wl_list_remove(&popup->map.link);
wl_list_remove(&popup->unmap.link);
wl_list_remove(&popup->destroy.link);
wl_list_remove(&popup->commit.link);
free(popup);
}
static void popup_unconstrain(struct sway_layer_popup *popup) {
struct sway_layer_surface *layer = popup_get_layer(popup);
struct wlr_xdg_popup *wlr_popup = popup->wlr_popup;
@ -554,6 +562,39 @@ static void popup_unconstrain(struct sway_layer_popup *popup) {
wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box);
}
static void popup_handle_map(struct wl_listener *listener, void *data) {
struct sway_layer_popup *popup = wl_container_of(listener, popup, map);
struct sway_layer_surface *layer = popup_get_layer(popup);
struct wlr_output *wlr_output = layer->layer_surface->output;
sway_assert(wlr_output, "wlr_layer_surface_v1 has null output");
surface_enter_output(popup->wlr_popup->base->surface, wlr_output->data);
popup_damage(popup, true);
}
static void popup_handle_unmap(struct wl_listener *listener, void *data) {
struct sway_layer_popup *popup = wl_container_of(listener, popup, unmap);
popup_damage(popup, true);
}
static void popup_handle_commit(struct wl_listener *listener, void *data) {
struct sway_layer_popup *popup = wl_container_of(listener, popup, commit);
if (popup->wlr_popup->base->initial_commit) {
popup_unconstrain(popup);
}
popup_damage(popup, false);
}
static void popup_handle_destroy(struct wl_listener *listener, void *data) {
struct sway_layer_popup *popup =
wl_container_of(listener, popup, destroy);
wl_list_remove(&popup->map.link);
wl_list_remove(&popup->unmap.link);
wl_list_remove(&popup->destroy.link);
wl_list_remove(&popup->commit.link);
free(popup);
}
static void popup_handle_new_popup(struct wl_listener *listener, void *data);
static struct sway_layer_popup *create_popup(struct wlr_xdg_popup *wlr_popup,
@ -569,9 +610,9 @@ static struct sway_layer_popup *create_popup(struct wlr_xdg_popup *wlr_popup,
popup->parent_layer = parent;
popup->map.notify = popup_handle_map;
wl_signal_add(&wlr_popup->base->events.map, &popup->map);
wl_signal_add(&wlr_popup->base->surface->events.map, &popup->map);
popup->unmap.notify = popup_handle_unmap;
wl_signal_add(&wlr_popup->base->events.unmap, &popup->unmap);
wl_signal_add(&wlr_popup->base->surface->events.unmap, &popup->unmap);
popup->destroy.notify = popup_handle_destroy;
wl_signal_add(&wlr_popup->base->events.destroy, &popup->destroy);
popup->commit.notify = popup_handle_commit;
@ -579,8 +620,6 @@ static struct sway_layer_popup *create_popup(struct wlr_xdg_popup *wlr_popup,
popup->new_popup.notify = popup_handle_new_popup;
wl_signal_add(&wlr_popup->base->events.new_popup, &popup->new_popup);
popup_unconstrain(popup);
return popup;
}
@ -659,9 +698,9 @@ void handle_layer_shell_surface(struct wl_listener *listener, void *data) {
sway_layer->destroy.notify = handle_destroy;
wl_signal_add(&layer_surface->events.destroy, &sway_layer->destroy);
sway_layer->map.notify = handle_map;
wl_signal_add(&layer_surface->events.map, &sway_layer->map);
wl_signal_add(&layer_surface->surface->events.map, &sway_layer->map);
sway_layer->unmap.notify = handle_unmap;
wl_signal_add(&layer_surface->events.unmap, &sway_layer->unmap);
wl_signal_add(&layer_surface->surface->events.unmap, &sway_layer->unmap);
sway_layer->new_popup.notify = handle_new_popup;
wl_signal_add(&layer_surface->events.new_popup, &sway_layer->new_popup);
sway_layer->new_subsurface.notify = handle_new_subsurface;

View file

@ -6,14 +6,17 @@
#include <wayland-server-core.h>
#include <wlr/config.h>
#include <wlr/backend/headless.h>
#include <wlr/render/swapchain.h>
#include <wlr/render/wlr_renderer.h>
#include <wlr/types/wlr_buffer.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.h>
#include <wlr/types/wlr_presentation_time.h>
#include <wlr/types/wlr_compositor.h>
#include <wlr/util/region.h>
#include <wlr/util/transform.h>
#include "config.h"
#include "log.h"
#include "sway/config.h"
@ -36,13 +39,22 @@
#include <wlr/types/wlr_drm_lease_v1.h>
#endif
bool output_match_name_or_id(struct sway_output *output,
const char *name_or_id) {
if (strcmp(name_or_id, "*") == 0) {
return true;
}
char identifier[128];
output_get_identifier(identifier, sizeof(identifier), output);
return strcasecmp(identifier, name_or_id) == 0
|| strcasecmp(output->wlr_output->name, name_or_id) == 0;
}
struct sway_output *output_by_name_or_id(const char *name_or_id) {
for (int i = 0; i < root->outputs->length; ++i) {
struct sway_output *output = root->outputs->items[i];
char identifier[128];
output_get_identifier(identifier, sizeof(identifier), output);
if (strcasecmp(identifier, name_or_id) == 0
|| strcasecmp(output->wlr_output->name, name_or_id) == 0) {
if (output_match_name_or_id(output, name_or_id)) {
return output;
}
}
@ -52,10 +64,7 @@ struct sway_output *output_by_name_or_id(const char *name_or_id) {
struct sway_output *all_output_by_name_or_id(const char *name_or_id) {
struct sway_output *output;
wl_list_for_each(output, &root->all_outputs, link) {
char identifier[128];
output_get_identifier(identifier, sizeof(identifier), output);
if (strcasecmp(identifier, name_or_id) == 0
|| strcasecmp(output->wlr_output->name, name_or_id) == 0) {
if (output_match_name_or_id(output, name_or_id)) {
return output;
}
}
@ -258,7 +267,7 @@ void output_drag_icons_for_each_surface(struct sway_output *output,
double ox = drag_icon->x - output->lx;
double oy = drag_icon->y - output->ly;
if (drag_icon->wlr_drag_icon->mapped) {
if (drag_icon->wlr_drag_icon->surface->mapped) {
output_surface_for_each_surface(output,
drag_icon->wlr_drag_icon->surface, ox, oy,
iterator, user_data);
@ -288,7 +297,7 @@ static void output_for_each_surface(struct sway_output *output,
if (lock_surface->output != output->wlr_output) {
continue;
}
if (!lock_surface->mapped) {
if (!lock_surface->surface->mapped) {
continue;
}
@ -450,7 +459,7 @@ static void count_surface_iterator(struct sway_output *output,
}
static bool scan_out_fullscreen_view(struct sway_output *output,
struct sway_view *view) {
struct wlr_output_state *pending, struct sway_view *view) {
struct wlr_output *wlr_output = output->wlr_output;
struct sway_workspace *workspace = output->current.active_workspace;
if (!sway_assert(workspace, "Expected an active workspace")) {
@ -512,15 +521,20 @@ static bool scan_out_fullscreen_view(struct sway_output *output,
return false;
}
wlr_output_attach_buffer(wlr_output, &surface->buffer->base);
if (!wlr_output_test(wlr_output)) {
if (!wlr_output_is_direct_scanout_allowed(wlr_output)) {
return false;
}
wlr_presentation_surface_sampled_on_output(server.presentation, surface,
wlr_output_state_set_buffer(pending, &surface->buffer->base);
if (!wlr_output_test_state(wlr_output, pending)) {
return false;
}
wlr_presentation_surface_scanned_out_on_output(server.presentation, surface,
wlr_output);
return wlr_output_commit(wlr_output);
return wlr_output_commit_state(wlr_output, pending);
}
static void get_frame_damage(struct sway_output *output,
@ -552,6 +566,12 @@ static int output_repaint_timer_handler(void *data) {
wlr_output->frame_pending = false;
if (!wlr_output->needs_frame &&
!output->gamma_lut_changed &&
!pixman_region32_not_empty(&output->damage_ring.current)) {
return 0;
}
struct sway_workspace *workspace = output->current.active_workspace;
if (workspace == NULL) {
return 0;
@ -562,11 +582,31 @@ static int output_repaint_timer_handler(void *data) {
fullscreen_con = workspace->current.fullscreen;
}
struct wlr_output_state pending = {0};
if (output->gamma_lut_changed) {
output->gamma_lut_changed = false;
struct wlr_gamma_control_v1 *gamma_control =
wlr_gamma_control_manager_v1_get_control(
server.gamma_control_manager_v1, wlr_output);
if (!wlr_gamma_control_v1_apply(gamma_control, &pending)) {
goto out;
}
if (!wlr_output_test_state(wlr_output, &pending)) {
wlr_output_state_finish(&pending);
pending = (struct wlr_output_state){0};
wlr_gamma_control_v1_send_failed_and_destroy(gamma_control);
}
}
pending.committed |= WLR_OUTPUT_STATE_DAMAGE;
get_frame_damage(output, &pending.damage);
if (fullscreen_con && fullscreen_con->view && !debug.noscanout) {
// Try to scan-out the fullscreen view
static bool last_scanned_out = false;
bool scanned_out =
scan_out_fullscreen_view(output, fullscreen_con->view);
scan_out_fullscreen_view(output, &pending, fullscreen_con->view);
if (scanned_out && !last_scanned_out) {
sway_log(SWAY_DEBUG, "Scanning out fullscreen view on %s",
@ -580,43 +620,68 @@ static int output_repaint_timer_handler(void *data) {
last_scanned_out = scanned_out;
if (scanned_out) {
return 0;
goto out;
}
}
if (!output->wlr_output->needs_frame &&
!pixman_region32_not_empty(&output->damage_ring.current)) {
return 0;
if (!wlr_output_configure_primary_swapchain(wlr_output, &pending, &wlr_output->swapchain)) {
goto out;
}
int buffer_age;
if (!wlr_output_attach_render(output->wlr_output, &buffer_age)) {
return 0;
struct wlr_buffer *buffer = wlr_swapchain_acquire(wlr_output->swapchain, &buffer_age);
if (buffer == NULL) {
goto out;
}
struct wlr_render_pass *render_pass = wlr_renderer_begin_buffer_pass(
wlr_output->renderer, buffer, NULL);
if (render_pass == NULL) {
wlr_buffer_unlock(buffer);
goto out;
}
pixman_region32_t damage;
pixman_region32_init(&damage);
wlr_damage_ring_get_buffer_damage(&output->damage_ring, buffer_age, &damage);
if (debug.damage == DAMAGE_RERENDER) {
int width, height;
wlr_output_transformed_resolution(wlr_output, &width, &height);
pixman_region32_union_rect(&damage, &damage, 0, 0, width, height);
}
struct render_context ctx = {
.output_damage = &damage,
.renderer = wlr_output->renderer,
.output = output,
.pass = render_pass,
};
struct timespec now;
clock_gettime(CLOCK_MONOTONIC, &now);
output_render(output, &damage);
output_render(&ctx);
pixman_region32_fini(&damage);
pixman_region32_t frame_damage;
get_frame_damage(output, &frame_damage);
wlr_output_set_damage(wlr_output, &frame_damage);
pixman_region32_fini(&frame_damage);
if (!wlr_render_pass_submit(render_pass)) {
wlr_buffer_unlock(buffer);
goto out;
}
if (!wlr_output_commit(wlr_output)) {
return 0;
wlr_output_state_set_buffer(&pending, buffer);
wlr_buffer_unlock(buffer);
if (!wlr_output_commit_state(wlr_output, &pending)) {
goto out;
}
wlr_damage_ring_rotate(&output->damage_ring);
output->last_frame = now;
out:
wlr_output_state_finish(&pending);
return 0;
}
@ -642,9 +707,7 @@ static void handle_frame(struct wl_listener *listener, void *user_data) {
if (output->max_render_time != 0) {
struct timespec now;
clockid_t presentation_clock
= wlr_backend_get_presentation_clock(server.backend);
clock_gettime(presentation_clock, &now);
clock_gettime(CLOCK_MONOTONIC, &now);
const long NSEC_IN_SECONDS = 1000000000;
struct timespec predicted_refresh = output->last_presentation;
@ -819,12 +882,9 @@ static void update_output_manager_config(struct sway_server *server) {
wlr_output_layout_get_box(root->output_layout,
output->wlr_output, &output_box);
// We mark the output enabled when it's switched off but not disabled
config_head->state.enabled = output->current_mode != NULL && output->enabled;
config_head->state.mode = output->current_mode;
if (!wlr_box_empty(&output_box)) {
config_head->state.x = output_box.x;
config_head->state.y = output_box.y;
}
config_head->state.enabled = !wlr_box_empty(&output_box);
config_head->state.x = output_box.x;
config_head->state.y = output_box.y;
}
wlr_output_manager_v1_set_configuration(server->output_manager_v1, config);
@ -862,36 +922,6 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
update_output_manager_config(server);
}
static void handle_mode(struct sway_output *output) {
if (!output->enabled && !output->enabling) {
struct output_config *oc = find_output_config(output);
if (output->wlr_output->current_mode != NULL &&
(!oc || oc->enabled)) {
// We want to enable this output, but it didn't work last time,
// possibly because we hadn't enough CRTCs. Try again now that the
// output has a mode.
sway_log(SWAY_DEBUG, "Output %s has gained a CRTC, "
"trying to enable it", output->wlr_output->name);
apply_output_config(oc, output);
}
return;
}
if (!output->enabled) {
return;
}
arrange_layers(output);
arrange_output(output);
transaction_commit_dirty();
int width, height;
wlr_output_transformed_resolution(output->wlr_output, &width, &height);
wlr_damage_ring_set_bounds(&output->damage_ring, width, height);
wlr_output_schedule_frame(output->wlr_output);
update_output_manager_config(output->server);
}
static void update_textures(struct sway_container *con, void *data) {
container_update_title_textures(con);
container_update_marks_textures(con);
@ -907,20 +937,19 @@ 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 (event->committed & WLR_OUTPUT_STATE_MODE) {
handle_mode(output);
}
if (!output->enabled) {
return;
}
if (event->committed & WLR_OUTPUT_STATE_SCALE) {
if (event->state->committed & WLR_OUTPUT_STATE_SCALE) {
output_for_each_container(output, update_textures, NULL);
output_for_each_surface(output, update_output_scale_iterator, NULL);
}
if (event->committed & (WLR_OUTPUT_STATE_TRANSFORM | WLR_OUTPUT_STATE_SCALE)) {
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();
@ -928,12 +957,19 @@ static void handle_commit(struct wl_listener *listener, void *data) {
update_output_manager_config(output->server);
}
if (event->committed & (WLR_OUTPUT_STATE_MODE | WLR_OUTPUT_STATE_TRANSFORM)) {
if (event->state->committed & (
WLR_OUTPUT_STATE_MODE |
WLR_OUTPUT_STATE_TRANSFORM)) {
int width, height;
wlr_output_transformed_resolution(output->wlr_output, &width, &height);
wlr_damage_ring_set_bounds(&output->damage_ring, width, height);
wlr_output_schedule_frame(output->wlr_output);
}
// 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) {
@ -999,9 +1035,6 @@ void handle_new_output(struct wl_listener *listener, void *data) {
}
output->server = server;
wlr_damage_ring_init(&output->damage_ring);
int width, height;
wlr_output_transformed_resolution(output->wlr_output, &width, &height);
wlr_damage_ring_set_bounds(&output->damage_ring, width, height);
wl_signal_add(&wlr_output->events.destroy, &output->destroy);
output->destroy.notify = handle_destroy;
@ -1027,6 +1060,9 @@ void handle_new_output(struct wl_listener *listener, void *data) {
transaction_commit_dirty();
int width, height;
wlr_output_transformed_resolution(output->wlr_output, &width, &height);
wlr_damage_ring_set_bounds(&output->damage_ring, width, height);
update_output_manager_config(server);
}
@ -1037,6 +1073,21 @@ void handle_output_layout_change(struct wl_listener *listener,
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 void output_manager_apply(struct sway_server *server,
struct wlr_output_configuration_v1 *config, bool test_only) {
// TODO: perform atomic tests on the whole backend atomically

File diff suppressed because it is too large Load diff

View file

@ -56,6 +56,7 @@ void surface_update_outputs(struct wlr_surface *surface) {
}
}
wlr_fractional_scale_v1_notify_scale(surface, scale);
wlr_surface_set_preferred_buffer_scale(surface, ceil(scale));
}
void surface_enter_output(struct wlr_surface *surface,

View file

@ -344,7 +344,7 @@ static void transaction_progress(void) {
server.queued_transaction = NULL;
if (!server.pending_transaction) {
sway_idle_inhibit_v1_check_active(server.idle_inhibit_manager_v1);
sway_idle_inhibit_v1_check_active();
return;
}

View file

@ -38,6 +38,7 @@ static void popup_destroy(struct sway_view_child *child) {
return;
}
struct sway_xdg_popup *popup = (struct sway_xdg_popup *)child;
wl_list_remove(&popup->surface_commit.link);
wl_list_remove(&popup->new_popup.link);
wl_list_remove(&popup->destroy.link);
free(popup);
@ -51,23 +52,17 @@ static const struct sway_view_child_impl popup_impl = {
static struct sway_xdg_popup *popup_create(
struct wlr_xdg_popup *wlr_popup, struct sway_view *view);
static void popup_handle_new_popup(struct wl_listener *listener, void *data) {
struct sway_xdg_popup *popup =
wl_container_of(listener, popup, new_popup);
struct wlr_xdg_popup *wlr_popup = data;
popup_create(wlr_popup, popup->child.view);
}
static void popup_handle_destroy(struct wl_listener *listener, void *data) {
struct sway_xdg_popup *popup = wl_container_of(listener, popup, destroy);
view_child_destroy(&popup->child);
}
static void popup_unconstrain(struct sway_xdg_popup *popup) {
struct sway_view *view = popup->child.view;
struct wlr_xdg_popup *wlr_popup = popup->wlr_xdg_popup;
struct sway_output *output = view->container->pending.workspace->output;
struct sway_workspace *workspace = view->container->pending.workspace;
if (!workspace) {
// is null if in the scratchpad
return;
}
struct sway_output *output = workspace->output;
// the output box expressed in the coordinate system of the toplevel parent
// of the popup
@ -81,6 +76,25 @@ static void popup_unconstrain(struct sway_xdg_popup *popup) {
wlr_xdg_popup_unconstrain_from_box(wlr_popup, &output_toplevel_sx_box);
}
static void popup_handle_surface_commit(struct wl_listener *listener, void *data) {
struct sway_xdg_popup *popup = wl_container_of(listener, popup, surface_commit);
if (popup->wlr_xdg_popup->base->initial_commit) {
popup_unconstrain(popup);
}
}
static void popup_handle_new_popup(struct wl_listener *listener, void *data) {
struct sway_xdg_popup *popup =
wl_container_of(listener, popup, new_popup);
struct wlr_xdg_popup *wlr_popup = data;
popup_create(wlr_popup, popup->child.view);
}
static void popup_handle_destroy(struct wl_listener *listener, void *data) {
struct sway_xdg_popup *popup = wl_container_of(listener, popup, destroy);
view_child_destroy(&popup->child);
}
static struct sway_xdg_popup *popup_create(
struct wlr_xdg_popup *wlr_popup, struct sway_view *view) {
struct wlr_xdg_surface *xdg_surface = wlr_popup->base;
@ -91,22 +105,21 @@ static struct sway_xdg_popup *popup_create(
return NULL;
}
view_child_init(&popup->child, &popup_impl, view, xdg_surface->surface);
popup->wlr_xdg_popup = xdg_surface->popup;
popup->wlr_xdg_popup = wlr_popup;
wl_signal_add(&xdg_surface->surface->events.commit, &popup->surface_commit);
popup->surface_commit.notify = popup_handle_surface_commit;
wl_signal_add(&xdg_surface->events.new_popup, &popup->new_popup);
popup->new_popup.notify = popup_handle_new_popup;
wl_signal_add(&xdg_surface->events.destroy, &popup->destroy);
wl_signal_add(&wlr_popup->events.destroy, &popup->destroy);
popup->destroy.notify = popup_handle_destroy;
wl_signal_add(&xdg_surface->events.map, &popup->child.surface_map);
wl_signal_add(&xdg_surface->events.unmap, &popup->child.surface_unmap);
popup_unconstrain(popup);
wl_signal_add(&xdg_surface->surface->events.map, &popup->child.surface_map);
wl_signal_add(&xdg_surface->surface->events.unmap, &popup->child.surface_unmap);
return popup;
}
static struct sway_xdg_shell_view *xdg_shell_view_from_view(
struct sway_view *view) {
if (!sway_assert(view->type == SWAY_VIEW_XDG_SHELL,
@ -163,12 +176,19 @@ static void set_tiled(struct sway_view *view, bool tiled) {
if (xdg_shell_view_from_view(view) == NULL) {
return;
}
enum wlr_edges edges = WLR_EDGE_NONE;
if (tiled) {
edges = WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP |
WLR_EDGE_BOTTOM;
if (wl_resource_get_version(view->wlr_xdg_toplevel->resource) >=
XDG_TOPLEVEL_STATE_TILED_LEFT_SINCE_VERSION) {
enum wlr_edges edges = WLR_EDGE_NONE;
if (tiled) {
edges = WLR_EDGE_LEFT | WLR_EDGE_RIGHT | WLR_EDGE_TOP |
WLR_EDGE_BOTTOM;
}
wlr_xdg_toplevel_set_tiled(view->wlr_xdg_toplevel, edges);
} else {
// The version is too low for the tiled state; configure as maximized instead
// to stop the client from drawing decorations outside of the toplevel geometry.
wlr_xdg_toplevel_set_maximized(view->wlr_xdg_toplevel, tiled);
}
wlr_xdg_toplevel_set_tiled(view->wlr_xdg_toplevel, edges);
}
static void set_fullscreen(struct sway_view *view, bool fullscreen) {
@ -273,6 +293,19 @@ static void handle_commit(struct wl_listener *listener, void *data) {
struct sway_view *view = &xdg_shell_view->view;
struct wlr_xdg_surface *xdg_surface = view->wlr_xdg_toplevel->base;
if (xdg_surface->initial_commit) {
if (view->xdg_decoration != NULL) {
set_xdg_decoration_mode(view->xdg_decoration);
}
// XXX: https://github.com/swaywm/sway/issues/2176
wlr_xdg_surface_schedule_configure(xdg_surface);
return;
}
if (!xdg_surface->surface->mapped) {
return;
}
struct wlr_box new_geo;
wlr_xdg_surface_get_geometry(xdg_surface, &new_geo);
bool new_size = new_geo.width != view->geometry.width ||
@ -288,6 +321,11 @@ static void handle_commit(struct wl_listener *listener, void *data) {
memcpy(&view->geometry, &new_geo, sizeof(struct wlr_box));
if (container_is_floating(view->container)) {
view_update_size(view);
// Only set the toplevel size the current container actually has a size.
if (view->container->current.width) {
wlr_xdg_toplevel_set_size(view->wlr_xdg_toplevel, view->geometry.width,
view->geometry.height);
}
transaction_commit_dirty_client();
} else {
view_center_surface(view);
@ -338,7 +376,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
struct wlr_xdg_toplevel *toplevel = xdg_shell_view->view.wlr_xdg_toplevel;
struct sway_view *view = &xdg_shell_view->view;
if (!toplevel->base->mapped) {
if (!toplevel->base->surface->mapped) {
return;
}
@ -403,7 +441,6 @@ static void handle_unmap(struct wl_listener *listener, void *data) {
view_unmap(view);
wl_list_remove(&xdg_shell_view->commit.link);
wl_list_remove(&xdg_shell_view->new_popup.link);
wl_list_remove(&xdg_shell_view->request_maximize.link);
wl_list_remove(&xdg_shell_view->request_fullscreen.link);
@ -446,10 +483,6 @@ static void handle_map(struct wl_listener *listener, void *data) {
transaction_commit_dirty();
xdg_shell_view->commit.notify = handle_commit;
wl_signal_add(&toplevel->base->surface->events.commit,
&xdg_shell_view->commit);
xdg_shell_view->new_popup.notify = handle_new_popup;
wl_signal_add(&toplevel->base->events.new_popup,
&xdg_shell_view->new_popup);
@ -489,6 +522,7 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&xdg_shell_view->destroy.link);
wl_list_remove(&xdg_shell_view->map.link);
wl_list_remove(&xdg_shell_view->unmap.link);
wl_list_remove(&xdg_shell_view->commit.link);
view->wlr_xdg_toplevel = NULL;
if (view->xdg_decoration) {
view->xdg_decoration->view = NULL;
@ -501,17 +535,12 @@ struct sway_view *view_from_wlr_xdg_surface(
return xdg_surface->data;
}
void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {
struct wlr_xdg_surface *xdg_surface = data;
if (xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP) {
sway_log(SWAY_DEBUG, "New xdg_shell popup");
return;
}
void handle_xdg_shell_toplevel(struct wl_listener *listener, void *data) {
struct wlr_xdg_toplevel *xdg_toplevel = data;
sway_log(SWAY_DEBUG, "New xdg_shell toplevel title='%s' app_id='%s'",
xdg_surface->toplevel->title, xdg_surface->toplevel->app_id);
wlr_xdg_surface_ping(xdg_surface);
xdg_toplevel->title, xdg_toplevel->app_id);
wlr_xdg_surface_ping(xdg_toplevel->base);
struct sway_xdg_shell_view *xdg_shell_view =
calloc(1, sizeof(struct sway_xdg_shell_view));
@ -520,16 +549,20 @@ void handle_xdg_shell_surface(struct wl_listener *listener, void *data) {
}
view_init(&xdg_shell_view->view, SWAY_VIEW_XDG_SHELL, &view_impl);
xdg_shell_view->view.wlr_xdg_toplevel = xdg_surface->toplevel;
xdg_shell_view->view.wlr_xdg_toplevel = xdg_toplevel;
xdg_shell_view->map.notify = handle_map;
wl_signal_add(&xdg_surface->events.map, &xdg_shell_view->map);
wl_signal_add(&xdg_toplevel->base->surface->events.map, &xdg_shell_view->map);
xdg_shell_view->unmap.notify = handle_unmap;
wl_signal_add(&xdg_surface->events.unmap, &xdg_shell_view->unmap);
wl_signal_add(&xdg_toplevel->base->surface->events.unmap, &xdg_shell_view->unmap);
xdg_shell_view->commit.notify = handle_commit;
wl_signal_add(&xdg_toplevel->base->surface->events.commit,
&xdg_shell_view->commit);
xdg_shell_view->destroy.notify = handle_destroy;
wl_signal_add(&xdg_surface->events.destroy, &xdg_shell_view->destroy);
wl_signal_add(&xdg_toplevel->events.destroy, &xdg_shell_view->destroy);
xdg_surface->data = xdg_shell_view;
xdg_toplevel->base->data = xdg_shell_view;
}

View file

@ -125,8 +125,10 @@ static void unmanaged_handle_unmap(struct wl_listener *listener, void *data) {
}
static void unmanaged_handle_request_activate(struct wl_listener *listener, void *data) {
struct wlr_xwayland_surface *xsurface = data;
if (!xsurface->mapped) {
struct sway_xwayland_unmanaged *surface =
wl_container_of(listener, surface, request_activate);
struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
if (xsurface->surface == NULL || !xsurface->surface->mapped) {
return;
}
struct sway_seat *seat = input_manager_current_seat();
@ -138,12 +140,29 @@ static void unmanaged_handle_request_activate(struct wl_listener *listener, void
seat_set_focus_surface(seat, xsurface->surface, false);
}
static void unmanaged_handle_associate(struct wl_listener *listener, void *data) {
struct sway_xwayland_unmanaged *surface =
wl_container_of(listener, surface, associate);
struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
wl_signal_add(&xsurface->surface->events.map, &surface->map);
surface->map.notify = unmanaged_handle_map;
wl_signal_add(&xsurface->surface->events.unmap, &surface->unmap);
surface->unmap.notify = unmanaged_handle_unmap;
}
static void unmanaged_handle_dissociate(struct wl_listener *listener, void *data) {
struct sway_xwayland_unmanaged *surface =
wl_container_of(listener, surface, dissociate);
wl_list_remove(&surface->map.link);
wl_list_remove(&surface->unmap.link);
}
static void unmanaged_handle_destroy(struct wl_listener *listener, void *data) {
struct sway_xwayland_unmanaged *surface =
wl_container_of(listener, surface, destroy);
wl_list_remove(&surface->request_configure.link);
wl_list_remove(&surface->map.link);
wl_list_remove(&surface->unmap.link);
wl_list_remove(&surface->associate.link);
wl_list_remove(&surface->dissociate.link);
wl_list_remove(&surface->destroy.link);
wl_list_remove(&surface->override_redirect.link);
wl_list_remove(&surface->request_activate.link);
@ -159,7 +178,7 @@ static void unmanaged_handle_override_redirect(struct wl_listener *listener, voi
wl_container_of(listener, surface, override_redirect);
struct wlr_xwayland_surface *xsurface = surface->wlr_xwayland_surface;
bool mapped = xsurface->mapped;
bool mapped = xsurface->surface != NULL && xsurface->surface->mapped;
if (mapped) {
unmanaged_handle_unmap(&surface->unmap, NULL);
}
@ -186,10 +205,10 @@ static struct sway_xwayland_unmanaged *create_unmanaged(
wl_signal_add(&xsurface->events.request_configure,
&surface->request_configure);
surface->request_configure.notify = unmanaged_handle_request_configure;
wl_signal_add(&xsurface->events.map, &surface->map);
surface->map.notify = unmanaged_handle_map;
wl_signal_add(&xsurface->events.unmap, &surface->unmap);
surface->unmap.notify = unmanaged_handle_unmap;
wl_signal_add(&xsurface->events.associate, &surface->associate);
surface->associate.notify = unmanaged_handle_associate;
wl_signal_add(&xsurface->events.dissociate, &surface->dissociate);
surface->dissociate.notify = unmanaged_handle_dissociate;
wl_signal_add(&xsurface->events.destroy, &surface->destroy);
surface->destroy.notify = unmanaged_handle_destroy;
wl_signal_add(&xsurface->events.set_override_redirect, &surface->override_redirect);
@ -472,8 +491,8 @@ static void handle_destroy(struct wl_listener *listener, void *data) {
wl_list_remove(&xwayland_view->set_window_type.link);
wl_list_remove(&xwayland_view->set_hints.link);
wl_list_remove(&xwayland_view->set_decorations.link);
wl_list_remove(&xwayland_view->map.link);
wl_list_remove(&xwayland_view->unmap.link);
wl_list_remove(&xwayland_view->associate.link);
wl_list_remove(&xwayland_view->dissociate.link);
wl_list_remove(&xwayland_view->override_redirect.link);
view_begin_destroy(&xwayland_view->view);
}
@ -495,8 +514,8 @@ static void handle_unmap(struct wl_listener *listener, void *data) {
static void handle_map(struct wl_listener *listener, void *data) {
struct sway_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, map);
struct wlr_xwayland_surface *xsurface = data;
struct sway_view *view = &xwayland_view->view;
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
view->natural_width = xsurface->width;
view->natural_height = xsurface->height;
@ -515,10 +534,10 @@ static void handle_map(struct wl_listener *listener, void *data) {
static void handle_override_redirect(struct wl_listener *listener, void *data) {
struct sway_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, override_redirect);
struct wlr_xwayland_surface *xsurface = data;
struct sway_view *view = &xwayland_view->view;
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
bool mapped = xsurface->mapped;
bool mapped = xsurface->surface != NULL && xsurface->surface->mapped;
if (mapped) {
handle_unmap(&xwayland_view->unmap, NULL);
}
@ -537,7 +556,7 @@ static void handle_request_configure(struct wl_listener *listener, void *data) {
struct wlr_xwayland_surface_configure_event *ev = data;
struct sway_view *view = &xwayland_view->view;
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
if (!xsurface->mapped) {
if (xsurface->surface == NULL || !xsurface->surface->mapped) {
wlr_xwayland_surface_configure(xsurface, ev->x, ev->y,
ev->width, ev->height);
return;
@ -566,7 +585,7 @@ static void handle_request_fullscreen(struct wl_listener *listener, void *data)
wl_container_of(listener, xwayland_view, request_fullscreen);
struct sway_view *view = &xwayland_view->view;
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
if (!xsurface->mapped) {
if (xsurface->surface == NULL || !xsurface->surface->mapped) {
return;
}
container_set_fullscreen(view->container, xsurface->fullscreen);
@ -580,7 +599,7 @@ static void handle_request_minimize(struct wl_listener *listener, void *data) {
wl_container_of(listener, xwayland_view, request_minimize);
struct sway_view *view = &xwayland_view->view;
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
if (!xsurface->mapped) {
if (xsurface->surface == NULL || !xsurface->surface->mapped) {
return;
}
@ -595,7 +614,7 @@ static void handle_request_move(struct wl_listener *listener, void *data) {
wl_container_of(listener, xwayland_view, request_move);
struct sway_view *view = &xwayland_view->view;
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
if (!xsurface->mapped) {
if (xsurface->surface == NULL || !xsurface->surface->mapped) {
return;
}
if (!container_is_floating(view->container) ||
@ -611,7 +630,7 @@ static void handle_request_resize(struct wl_listener *listener, void *data) {
wl_container_of(listener, xwayland_view, request_resize);
struct sway_view *view = &xwayland_view->view;
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
if (!xsurface->mapped) {
if (xsurface->surface == NULL || !xsurface->surface->mapped) {
return;
}
if (!container_is_floating(view->container)) {
@ -627,7 +646,7 @@ static void handle_request_activate(struct wl_listener *listener, void *data) {
wl_container_of(listener, xwayland_view, request_activate);
struct sway_view *view = &xwayland_view->view;
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
if (!xsurface->mapped) {
if (xsurface->surface == NULL || !xsurface->surface->mapped) {
return;
}
view_request_activate(view, NULL);
@ -640,7 +659,7 @@ static void handle_set_title(struct wl_listener *listener, void *data) {
wl_container_of(listener, xwayland_view, set_title);
struct sway_view *view = &xwayland_view->view;
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
if (!xsurface->mapped) {
if (xsurface->surface == NULL || !xsurface->surface->mapped) {
return;
}
view_update_title(view, false);
@ -652,7 +671,7 @@ static void handle_set_class(struct wl_listener *listener, void *data) {
wl_container_of(listener, xwayland_view, set_class);
struct sway_view *view = &xwayland_view->view;
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
if (!xsurface->mapped) {
if (xsurface->surface == NULL || !xsurface->surface->mapped) {
return;
}
view_execute_criteria(view);
@ -663,7 +682,7 @@ static void handle_set_role(struct wl_listener *listener, void *data) {
wl_container_of(listener, xwayland_view, set_role);
struct sway_view *view = &xwayland_view->view;
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
if (!xsurface->mapped) {
if (xsurface->surface == NULL || !xsurface->surface->mapped) {
return;
}
view_execute_criteria(view);
@ -699,7 +718,7 @@ static void handle_set_window_type(struct wl_listener *listener, void *data) {
wl_container_of(listener, xwayland_view, set_window_type);
struct sway_view *view = &xwayland_view->view;
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
if (!xsurface->mapped) {
if (xsurface->surface == NULL || !xsurface->surface->mapped) {
return;
}
view_execute_criteria(view);
@ -710,7 +729,7 @@ static void handle_set_hints(struct wl_listener *listener, void *data) {
wl_container_of(listener, xwayland_view, set_hints);
struct sway_view *view = &xwayland_view->view;
struct wlr_xwayland_surface *xsurface = view->wlr_xwayland_surface;
if (!xsurface->mapped) {
if (xsurface->surface == NULL || !xsurface->surface->mapped) {
return;
}
const bool hints_urgency = xcb_icccm_wm_hints_get_urgency(xsurface->hints);
@ -725,6 +744,24 @@ static void handle_set_hints(struct wl_listener *listener, void *data) {
}
}
static void handle_associate(struct wl_listener *listener, void *data) {
struct sway_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, associate);
struct wlr_xwayland_surface *xsurface =
xwayland_view->view.wlr_xwayland_surface;
wl_signal_add(&xsurface->surface->events.unmap, &xwayland_view->unmap);
xwayland_view->unmap.notify = handle_unmap;
wl_signal_add(&xsurface->surface->events.map, &xwayland_view->map);
xwayland_view->map.notify = handle_map;
}
static void handle_dissociate(struct wl_listener *listener, void *data) {
struct sway_xwayland_view *xwayland_view =
wl_container_of(listener, xwayland_view, dissociate);
wl_list_remove(&xwayland_view->map.link);
wl_list_remove(&xwayland_view->unmap.link);
}
struct sway_view *view_from_wlr_xwayland_surface(
struct wlr_xwayland_surface *xsurface) {
return xsurface->data;
@ -794,11 +831,11 @@ struct sway_xwayland_view *create_xwayland_view(struct wlr_xwayland_surface *xsu
&xwayland_view->set_decorations);
xwayland_view->set_decorations.notify = handle_set_decorations;
wl_signal_add(&xsurface->events.unmap, &xwayland_view->unmap);
xwayland_view->unmap.notify = handle_unmap;
wl_signal_add(&xsurface->events.associate, &xwayland_view->associate);
xwayland_view->associate.notify = handle_associate;
wl_signal_add(&xsurface->events.map, &xwayland_view->map);
xwayland_view->map.notify = handle_map;
wl_signal_add(&xsurface->events.dissociate, &xwayland_view->dissociate);
xwayland_view->dissociate.notify = handle_dissociate;
wl_signal_add(&xsurface->events.set_override_redirect,
&xwayland_view->override_redirect);

View file

@ -7,7 +7,7 @@
#include <time.h>
#include <strings.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_idle.h>
#include <wlr/types/wlr_cursor_shape_v1.h>
#include <wlr/types/wlr_pointer.h>
#include <wlr/types/wlr_touch.h>
#include <wlr/types/wlr_tablet_v2.h>
@ -55,7 +55,8 @@ static struct wlr_surface *layer_surface_at(struct sway_output *output,
static bool surface_is_xdg_popup(struct wlr_surface *surface) {
struct wlr_xdg_surface *xdg_surface =
wlr_xdg_surface_try_from_wlr_surface(surface);
return xdg_surface != NULL && xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP;
return xdg_surface != NULL && xdg_surface->role == WLR_XDG_SURFACE_ROLE_POPUP &&
xdg_surface->popup != NULL;
}
static struct wlr_surface *layer_surface_popup_at(struct sway_output *output,
@ -236,7 +237,7 @@ void cursor_update_image(struct sway_cursor *cursor,
// Try a node's resize edge
enum wlr_edges edge = find_resize_edge(node->sway_container, NULL, cursor);
if (edge == WLR_EDGE_NONE) {
cursor_set_image(cursor, "left_ptr", NULL);
cursor_set_image(cursor, "default", NULL);
} else if (container_is_floating(node->sway_container)) {
cursor_set_image(cursor, wlr_xcursor_get_resize_name(edge), NULL);
} else {
@ -247,12 +248,12 @@ void cursor_update_image(struct sway_cursor *cursor,
}
}
} else {
cursor_set_image(cursor, "left_ptr", NULL);
cursor_set_image(cursor, "default", NULL);
}
}
static void cursor_hide(struct sway_cursor *cursor) {
wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0);
wlr_cursor_unset_image(cursor->cursor);
cursor->hidden = true;
wlr_seat_pointer_notify_clear_focus(cursor->seat->wlr_seat);
}
@ -509,6 +510,24 @@ static void handle_touch_up(struct wl_listener *listener, void *data) {
}
}
static void handle_touch_cancel(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor = wl_container_of(listener, cursor, touch_cancel);
struct wlr_touch_cancel_event *event = data;
cursor_handle_activity_from_device(cursor, &event->touch->base);
struct sway_seat *seat = cursor->seat;
if (cursor->simulating_pointer_from_touch) {
if (cursor->pointer_touch_id == cursor->seat->touch_id) {
cursor->pointer_touch_up = true;
dispatch_cursor_button(cursor, &event->touch->base,
event->time_msec, BTN_LEFT, WLR_BUTTON_RELEASED);
}
} else {
seatop_touch_cancel(seat, event);
}
}
static void handle_touch_motion(struct wl_listener *listener, void *data) {
struct sway_cursor *cursor =
wl_container_of(listener, cursor, touch_motion);
@ -1050,10 +1069,9 @@ void cursor_set_image(struct sway_cursor *cursor, const char *image,
}
if (!image) {
wlr_cursor_set_image(cursor->cursor, NULL, 0, 0, 0, 0, 0, 0);
wlr_cursor_unset_image(cursor->cursor);
} else if (!current_image || strcmp(current_image, image) != 0) {
wlr_xcursor_manager_set_cursor_image(cursor->xcursor_manager, image,
cursor->cursor);
wlr_cursor_set_xcursor(cursor->cursor, cursor->xcursor_manager, image);
}
}
@ -1100,6 +1118,7 @@ void sway_cursor_destroy(struct sway_cursor *cursor) {
wl_list_remove(&cursor->frame.link);
wl_list_remove(&cursor->touch_down.link);
wl_list_remove(&cursor->touch_up.link);
wl_list_remove(&cursor->touch_cancel.link);
wl_list_remove(&cursor->touch_motion.link);
wl_list_remove(&cursor->touch_frame.link);
wl_list_remove(&cursor->tool_axis.link);
@ -1136,9 +1155,6 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
wl_list_init(&cursor->image_surface_destroy.link);
cursor->image_surface_destroy.notify = handle_image_surface_destroy;
// gesture events
cursor->pointer_gestures = wlr_pointer_gestures_v1_create(server.wl_display);
wl_signal_add(&wlr_cursor->events.hold_begin, &cursor->hold_begin);
cursor->hold_begin.notify = handle_pointer_hold_begin;
wl_signal_add(&wlr_cursor->events.hold_end, &cursor->hold_end);
@ -1181,6 +1197,9 @@ struct sway_cursor *sway_cursor_create(struct sway_seat *seat) {
wl_signal_add(&wlr_cursor->events.touch_up, &cursor->touch_up);
cursor->touch_up.notify = handle_touch_up;
wl_signal_add(&wlr_cursor->events.touch_cancel, &cursor->touch_cancel);
cursor->touch_cancel.notify = handle_touch_cancel;
wl_signal_add(&wlr_cursor->events.touch_motion,
&cursor->touch_motion);
cursor->touch_motion.notify = handle_touch_motion;
@ -1273,11 +1292,7 @@ uint32_t get_mouse_bindsym(const char *name, char **error) {
// Get event code from name
int code = libevdev_event_code_from_name(EV_KEY, name);
if (code == -1) {
size_t len = snprintf(NULL, 0, "Unknown event %s", name) + 1;
*error = malloc(len);
if (*error) {
snprintf(*error, len, "Unknown event %s", name);
}
*error = format_str("Unknown event %s", name);
return 0;
}
return code;
@ -1299,13 +1314,8 @@ uint32_t get_mouse_bindcode(const char *name, char **error) {
}
const char *event = libevdev_event_code_get_name(EV_KEY, code);
if (!event || strncmp(event, "BTN_", strlen("BTN_")) != 0) {
size_t len = snprintf(NULL, 0, "Event code %d (%s) is not a button",
code, event ? event : "(null)") + 1;
*error = malloc(len);
if (*error) {
snprintf(*error, len, "Event code %d (%s) is not a button",
code, event ? event : "(null)");
}
*error = format_str("Event code %d (%s) is not a button",
code, event ? event : "(null)");
return 0;
}
return code;
@ -1458,3 +1468,26 @@ void sway_cursor_constrain(struct sway_cursor *cursor,
wl_signal_add(&constraint->surface->events.commit,
&cursor->constraint_commit);
}
void handle_request_set_cursor_shape(struct wl_listener *listener, void *data) {
const struct wlr_cursor_shape_manager_v1_request_set_shape_event *event = data;
struct sway_seat *seat = event->seat_client->seat->data;
if (!seatop_allows_set_cursor(seat)) {
return;
}
struct wl_client *focused_client = NULL;
struct wlr_surface *focused_surface = seat->wlr_seat->pointer_state.focused_surface;
if (focused_surface != NULL) {
focused_client = wl_resource_get_client(focused_surface->resource);
}
// TODO: check cursor mode
if (focused_client == NULL || event->seat_client->client != focused_client) {
sway_log(SWAY_DEBUG, "denying request to set cursor from unfocused client");
return;
}
cursor_set_image(seat->cursor, wlr_cursor_shape_v1_name(event->shape), focused_client);
}

View file

@ -6,7 +6,6 @@
#include <wlr/config.h>
#include <wlr/types/wlr_cursor.h>
#include <wlr/types/wlr_keyboard_group.h>
#include <wlr/types/wlr_input_inhibitor.h>
#include <wlr/types/wlr_virtual_keyboard_v1.h>
#include <wlr/types/wlr_virtual_pointer_v1.h>
#include "sway/config.h"
@ -80,15 +79,7 @@ char *input_device_get_identifier(struct wlr_input_device *device) {
}
}
const char *fmt = "%d:%d:%s";
int len = snprintf(NULL, 0, fmt, vendor, product, name) + 1;
char *identifier = malloc(len);
if (!identifier) {
sway_log(SWAY_ERROR, "Unable to allocate unique input device name");
return NULL;
}
snprintf(identifier, len, fmt, vendor, product, name);
char *identifier = format_str("%d:%d:%s", vendor, product, name);
free(name);
return identifier;
}
@ -292,34 +283,6 @@ static void handle_new_input(struct wl_listener *listener, void *data) {
}
}
static void handle_inhibit_activate(struct wl_listener *listener, void *data) {
struct sway_input_manager *input_manager = wl_container_of(
listener, input_manager, inhibit_activate);
struct sway_seat *seat;
wl_list_for_each(seat, &input_manager->seats, link) {
seat_set_exclusive_client(seat, input_manager->inhibit->active_client);
}
}
static void handle_inhibit_deactivate(struct wl_listener *listener, void *data) {
struct sway_input_manager *input_manager = wl_container_of(
listener, input_manager, inhibit_deactivate);
struct sway_seat *seat;
if (server.session_lock.locked) {
// Don't deactivate the grab of a screenlocker
return;
}
wl_list_for_each(seat, &input_manager->seats, link) {
seat_set_exclusive_client(seat, NULL);
struct sway_node *previous = seat_get_focus(seat);
if (previous) {
// Hack to get seat to re-focus the return value of get_focus
seat_set_focus(seat, NULL);
seat_set_focus(seat, previous);
}
}
}
static void handle_keyboard_shortcuts_inhibitor_destroy(
struct wl_listener *listener, void *data) {
struct sway_keyboard_shortcuts_inhibitor *sway_inhibitor =
@ -488,14 +451,6 @@ struct sway_input_manager *input_manager_create(struct sway_server *server) {
&input->virtual_pointer_new);
input->virtual_pointer_new.notify = handle_virtual_pointer;
input->inhibit = wlr_input_inhibit_manager_create(server->wl_display);
input->inhibit_activate.notify = handle_inhibit_activate;
wl_signal_add(&input->inhibit->events.activate,
&input->inhibit_activate);
input->inhibit_deactivate.notify = handle_inhibit_deactivate;
wl_signal_add(&input->inhibit->events.deactivate,
&input->inhibit_deactivate);
input->keyboard_shortcuts_inhibit =
wlr_keyboard_shortcuts_inhibit_v1_create(server->wl_display);
input->keyboard_shortcuts_inhibit_new_inhibitor.notify =
@ -503,6 +458,8 @@ struct sway_input_manager *input_manager_create(struct sway_server *server) {
wl_signal_add(&input->keyboard_shortcuts_inhibit->events.new_inhibitor,
&input->keyboard_shortcuts_inhibit_new_inhibitor);
input->pointer_gestures = wlr_pointer_gestures_v1_create(server->wl_display);
return input;
}
@ -540,6 +497,18 @@ static void retranslate_keysyms(struct input_config *input_config) {
return;
}
}
for (int i = 0; i < config->input_type_configs->length; ++i) {
struct input_config *ic = config->input_type_configs->items[i];
if (ic->xkb_layout || ic->xkb_file) {
// this is the first config with xkb_layout or xkb_file
if (ic->identifier == input_config->identifier) {
translate_keysyms(ic);
}
return;
}
}
}
static void input_manager_configure_input(
@ -558,10 +527,13 @@ static void input_manager_configure_input(
}
}
void input_manager_configure_all_inputs(void) {
struct sway_input_device *input_device = NULL;
void input_manager_configure_all_input_mappings(void) {
struct sway_input_device *input_device;
wl_list_for_each(input_device, &server.input->devices, link) {
input_manager_configure_input(input_device);
struct sway_seat *seat;
wl_list_for_each(seat, &server.input->seats, link) {
seat_configure_device_mapping(seat, input_device);
}
}
}

Some files were not shown because too many files have changed in this diff Show more