Use frame callbacks instead of vsync on Wayland
Instead of blocking on vsync, Alacritty now requests a notification from wayland about when the next frame should be rendered. this helps with input latency, since it gives alacritty more time to process events before a redraw. it also prevents alacritty from drawing unless the compositor tells it to do so. Fixes #2851.
This commit is contained in:
parent
a425fe6bfe
commit
04f0bcaf54
|
@ -33,6 +33,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
- Fallback to `LC_CTYPE=UTF-8` on macOS without valid system locale
|
- Fallback to `LC_CTYPE=UTF-8` on macOS without valid system locale
|
||||||
- Resize lag on launch under some X11 wms
|
- Resize lag on launch under some X11 wms
|
||||||
- Increased input latency due to vsync behavior on X11
|
- Increased input latency due to vsync behavior on X11
|
||||||
|
- Freeze when application is invisible on Wayland
|
||||||
|
|
||||||
## 0.4.2
|
## 0.4.2
|
||||||
|
|
||||||
|
|
|
@ -38,6 +38,7 @@ dependencies = [
|
||||||
"time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
"time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"urlocator 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
"urlocator 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"wayland-client 0.26.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"x11-dl 2.18.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"x11-dl 2.18.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
@ -1195,6 +1196,11 @@ dependencies = [
|
||||||
"objc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"objc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "once_cell"
|
||||||
|
version = "1.3.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "openssl"
|
name = "openssl"
|
||||||
version = "0.10.29"
|
version = "0.10.29"
|
||||||
|
@ -1532,6 +1538,11 @@ dependencies = [
|
||||||
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "scoped-tls"
|
||||||
|
version = "1.0.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "scopeguard"
|
name = "scopeguard"
|
||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
|
@ -1949,6 +1960,21 @@ dependencies = [
|
||||||
"wayland-sys 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"wayland-sys 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wayland-client"
|
||||||
|
version = "0.26.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"downcast-rs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"libc 0.2.69 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"nix 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"wayland-commons 0.26.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"wayland-scanner 0.26.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"wayland-sys 0.26.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wayland-commons"
|
name = "wayland-commons"
|
||||||
version = "0.23.6"
|
version = "0.23.6"
|
||||||
|
@ -1958,6 +1984,17 @@ dependencies = [
|
||||||
"wayland-sys 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
"wayland-sys 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wayland-commons"
|
||||||
|
version = "0.26.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"nix 0.17.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"once_cell 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"smallvec 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"wayland-sys 0.26.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wayland-protocols"
|
name = "wayland-protocols"
|
||||||
version = "0.23.6"
|
version = "0.23.6"
|
||||||
|
@ -1979,6 +2016,16 @@ dependencies = [
|
||||||
"xml-rs 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"xml-rs 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wayland-scanner"
|
||||||
|
version = "0.26.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"xml-rs 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wayland-sys"
|
name = "wayland-sys"
|
||||||
version = "0.23.6"
|
version = "0.23.6"
|
||||||
|
@ -1988,6 +2035,15 @@ dependencies = [
|
||||||
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "wayland-sys"
|
||||||
|
version = "0.26.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
dependencies = [
|
||||||
|
"dlib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "which"
|
name = "which"
|
||||||
version = "3.1.1"
|
version = "3.1.1"
|
||||||
|
@ -2295,6 +2351,7 @@ dependencies = [
|
||||||
"checksum objc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
|
"checksum objc 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
|
||||||
"checksum objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
|
"checksum objc-foundation 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1add1b659e36c9607c7aab864a76c7a4c2760cd0cd2e120f3fb8b952c7e22bf9"
|
||||||
"checksum objc_id 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
|
"checksum objc_id 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b"
|
||||||
|
"checksum once_cell 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1c601810575c99596d4afc46f78a678c80105117c379eb3650cf99b8a21ce5b"
|
||||||
"checksum openssl 0.10.29 (registry+https://github.com/rust-lang/crates.io-index)" = "cee6d85f4cb4c4f59a6a85d5b68a233d280c82e29e822913b9c8b129fbf20bdd"
|
"checksum openssl 0.10.29 (registry+https://github.com/rust-lang/crates.io-index)" = "cee6d85f4cb4c4f59a6a85d5b68a233d280c82e29e822913b9c8b129fbf20bdd"
|
||||||
"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
|
"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
|
||||||
"checksum openssl-sys 0.9.55 (registry+https://github.com/rust-lang/crates.io-index)" = "7717097d810a0f2e2323f9e5d11e71608355e24828410b55b9d4f18aa5f9a5d8"
|
"checksum openssl-sys 0.9.55 (registry+https://github.com/rust-lang/crates.io-index)" = "7717097d810a0f2e2323f9e5d11e71608355e24828410b55b9d4f18aa5f9a5d8"
|
||||||
|
@ -2337,6 +2394,7 @@ dependencies = [
|
||||||
"checksum ryu 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1"
|
"checksum ryu 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1"
|
||||||
"checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
"checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
|
||||||
"checksum schannel 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "039c25b130bd8c1321ee2d7de7fde2659fa9c2744e4bb29711cfc852ea53cd19"
|
"checksum schannel 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)" = "039c25b130bd8c1321ee2d7de7fde2659fa9c2744e4bb29711cfc852ea53cd19"
|
||||||
|
"checksum scoped-tls 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2"
|
||||||
"checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
"checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||||
"checksum security-framework 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "572dfa3a0785509e7a44b5b4bebcf94d41ba34e9ed9eb9df722545c3b3c4144a"
|
"checksum security-framework 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "572dfa3a0785509e7a44b5b4bebcf94d41ba34e9ed9eb9df722545c3b3c4144a"
|
||||||
"checksum security-framework-sys 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8ddb15a5fec93b7021b8a9e96009c5d8d51c15673569f7c0f6b7204e5b7b404f"
|
"checksum security-framework-sys 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8ddb15a5fec93b7021b8a9e96009c5d8d51c15673569f7c0f6b7204e5b7b404f"
|
||||||
|
@ -2389,10 +2447,14 @@ dependencies = [
|
||||||
"checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
|
"checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d"
|
||||||
"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||||
"checksum wayland-client 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "af1080ebe0efabcf12aef2132152f616038f2d7dcbbccf7b2d8c5270fe14bcda"
|
"checksum wayland-client 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "af1080ebe0efabcf12aef2132152f616038f2d7dcbbccf7b2d8c5270fe14bcda"
|
||||||
|
"checksum wayland-client 0.26.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6eda8c06906f6572f840930588ce28f021485bc9679af0191aeb753ad6c7b46b"
|
||||||
"checksum wayland-commons 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "bb66b0d1a27c39bbce712b6372131c6e25149f03ffb0cd017cf8f7de8d66dbdb"
|
"checksum wayland-commons 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "bb66b0d1a27c39bbce712b6372131c6e25149f03ffb0cd017cf8f7de8d66dbdb"
|
||||||
|
"checksum wayland-commons 0.26.3 (registry+https://github.com/rust-lang/crates.io-index)" = "951aaed76c01185bff7ec68426769c94e88b36113dfe73f8e2356feaa5f09c1f"
|
||||||
"checksum wayland-protocols 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc286643656742777d55dc8e70d144fa4699e426ca8e9d4ef454f4bf15ffcf9"
|
"checksum wayland-protocols 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc286643656742777d55dc8e70d144fa4699e426ca8e9d4ef454f4bf15ffcf9"
|
||||||
"checksum wayland-scanner 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93b02247366f395b9258054f964fe293ddd019c3237afba9be2ccbe9e1651c3d"
|
"checksum wayland-scanner 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93b02247366f395b9258054f964fe293ddd019c3237afba9be2ccbe9e1651c3d"
|
||||||
|
"checksum wayland-scanner 0.26.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21ae379761543b2f41ce88010d0f4ee489218c8e8cfa42dd8f070fdb263aa971"
|
||||||
"checksum wayland-sys 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d94e89a86e6d6d7c7c9b19ebf48a03afaac4af6bc22ae570e9a24124b75358f4"
|
"checksum wayland-sys 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d94e89a86e6d6d7c7c9b19ebf48a03afaac4af6bc22ae570e9a24124b75358f4"
|
||||||
|
"checksum wayland-sys 0.26.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fab1f1d2ab35838c5fcbbeebee42cf15721c5fdc1add1f13d0e70e219b94e013"
|
||||||
"checksum which 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724"
|
"checksum which 3.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d011071ae14a2f6671d0b74080ae0cd8ebf3a6f8c9589a2cd45f23126fe29724"
|
||||||
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
|
||||||
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
|
||||||
|
|
|
@ -41,6 +41,7 @@ dirs = "2.0.2"
|
||||||
|
|
||||||
[target.'cfg(not(any(target_os="windows", target_os="macos")))'.dependencies]
|
[target.'cfg(not(any(target_os="windows", target_os="macos")))'.dependencies]
|
||||||
x11-dl = "2"
|
x11-dl = "2"
|
||||||
|
wayland-client = { version = "0.26", features = ["dlopen"] }
|
||||||
|
|
||||||
[target.'cfg(windows)'.dependencies]
|
[target.'cfg(windows)'.dependencies]
|
||||||
winapi = { version = "0.3.7", features = ["impl-default", "wincon"]}
|
winapi = { version = "0.3.7", features = ["impl-default", "wincon"]}
|
||||||
|
|
|
@ -16,6 +16,8 @@
|
||||||
//! GPU drawing.
|
//! GPU drawing.
|
||||||
use std::f64;
|
use std::f64;
|
||||||
use std::fmt::{self, Formatter};
|
use std::fmt::{self, Formatter};
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
use std::sync::atomic::Ordering;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
use glutin::dpi::{PhysicalPosition, PhysicalSize};
|
use glutin::dpi::{PhysicalPosition, PhysicalSize};
|
||||||
|
@ -26,6 +28,8 @@ use glutin::platform::unix::EventLoopWindowTargetExtUnix;
|
||||||
use glutin::window::CursorIcon;
|
use glutin::window::CursorIcon;
|
||||||
use log::{debug, info};
|
use log::{debug, info};
|
||||||
use parking_lot::MutexGuard;
|
use parking_lot::MutexGuard;
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
use wayland_client::{Display as WaylandDisplay, EventQueue};
|
||||||
|
|
||||||
use font::{self, Rasterize};
|
use font::{self, Rasterize};
|
||||||
|
|
||||||
|
@ -47,16 +51,16 @@ use crate::window::{self, Window};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// Error with window management
|
/// Error with window management.
|
||||||
Window(window::Error),
|
Window(window::Error),
|
||||||
|
|
||||||
/// Error dealing with fonts
|
/// Error dealing with fonts.
|
||||||
Font(font::Error),
|
Font(font::Error),
|
||||||
|
|
||||||
/// Error in renderer
|
/// Error in renderer.
|
||||||
Render(renderer::Error),
|
Render(renderer::Error),
|
||||||
|
|
||||||
/// Error during buffer swap
|
/// Error during buffer swap.
|
||||||
ContextError(glutin::ContextError),
|
ContextError(glutin::ContextError),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,7 +110,7 @@ impl From<glutin::ContextError> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The display wraps a window, font rasterizer, and GPU renderer
|
/// The display wraps a window, font rasterizer, and GPU renderer.
|
||||||
pub struct Display {
|
pub struct Display {
|
||||||
pub size_info: SizeInfo,
|
pub size_info: SizeInfo,
|
||||||
pub window: Window,
|
pub window: Window,
|
||||||
|
@ -115,6 +119,9 @@ pub struct Display {
|
||||||
/// Currently highlighted URL.
|
/// Currently highlighted URL.
|
||||||
pub highlighted_url: Option<Url>,
|
pub highlighted_url: Option<Url>,
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
pub wayland_event_queue: Option<EventQueue>,
|
||||||
|
|
||||||
renderer: QuadRenderer,
|
renderer: QuadRenderer,
|
||||||
glyph_cache: GlyphCache,
|
glyph_cache: GlyphCache,
|
||||||
meter: Meter,
|
meter: Meter,
|
||||||
|
@ -124,11 +131,11 @@ pub struct Display {
|
||||||
|
|
||||||
impl Display {
|
impl Display {
|
||||||
pub fn new(config: &Config, event_loop: &EventLoop<Event>) -> Result<Display, Error> {
|
pub fn new(config: &Config, event_loop: &EventLoop<Event>) -> Result<Display, Error> {
|
||||||
// Guess DPR based on first monitor
|
// Guess DPR based on first monitor.
|
||||||
let estimated_dpr =
|
let estimated_dpr =
|
||||||
event_loop.available_monitors().next().map(|m| m.scale_factor()).unwrap_or(1.);
|
event_loop.available_monitors().next().map(|m| m.scale_factor()).unwrap_or(1.);
|
||||||
|
|
||||||
// Guess the target window dimensions
|
// Guess the target window dimensions.
|
||||||
let metrics = GlyphCache::static_metrics(config.font.clone(), estimated_dpr)?;
|
let metrics = GlyphCache::static_metrics(config.font.clone(), estimated_dpr)?;
|
||||||
let (cell_width, cell_height) = compute_cell_size(config, &metrics);
|
let (cell_width, cell_height) = compute_cell_size(config, &metrics);
|
||||||
let dimensions =
|
let dimensions =
|
||||||
|
@ -138,19 +145,37 @@ impl Display {
|
||||||
debug!("Estimated Cell Size: {} x {}", cell_width, cell_height);
|
debug!("Estimated Cell Size: {} x {}", cell_width, cell_height);
|
||||||
debug!("Estimated Dimensions: {:?}", dimensions);
|
debug!("Estimated Dimensions: {:?}", dimensions);
|
||||||
|
|
||||||
// Create the window where Alacritty will be displayed
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
let mut wayland_event_queue = None;
|
||||||
|
|
||||||
|
// Initialize Wayland event queue, to handle Wayland callbacks.
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
{
|
||||||
|
if let Some(display) = event_loop.wayland_display() {
|
||||||
|
let display = unsafe { WaylandDisplay::from_external_display(display as _) };
|
||||||
|
wayland_event_queue = Some(display.create_event_queue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the window where Alacritty will be displayed.
|
||||||
let size = dimensions.map(|(width, height)| PhysicalSize::new(width, height));
|
let size = dimensions.map(|(width, height)| PhysicalSize::new(width, height));
|
||||||
|
|
||||||
// Spawn window
|
// Spawn window.
|
||||||
let mut window = Window::new(event_loop, &config, size)?;
|
let mut window = Window::new(
|
||||||
|
event_loop,
|
||||||
|
&config,
|
||||||
|
size,
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
wayland_event_queue.as_ref(),
|
||||||
|
)?;
|
||||||
|
|
||||||
let dpr = window.scale_factor();
|
let dpr = window.scale_factor();
|
||||||
info!("Device pixel ratio: {}", dpr);
|
info!("Device pixel ratio: {}", dpr);
|
||||||
|
|
||||||
// get window properties for initializing the other subsystems
|
// get window properties for initializing the other subsystems.
|
||||||
let viewport_size = window.inner_size();
|
let viewport_size = window.inner_size();
|
||||||
|
|
||||||
// Create renderer
|
// Create renderer.
|
||||||
let mut renderer = QuadRenderer::new()?;
|
let mut renderer = QuadRenderer::new()?;
|
||||||
|
|
||||||
let (glyph_cache, cell_width, cell_height) =
|
let (glyph_cache, cell_width, cell_height) =
|
||||||
|
@ -169,7 +194,7 @@ impl Display {
|
||||||
window.set_inner_size(PhysicalSize::new(width, height));
|
window.set_inner_size(PhysicalSize::new(width, height));
|
||||||
}
|
}
|
||||||
} else if config.window.dynamic_padding {
|
} else if config.window.dynamic_padding {
|
||||||
// Make sure additional padding is spread evenly
|
// Make sure additional padding is spread evenly.
|
||||||
padding_x = dynamic_padding(padding_x, viewport_size.width as f32, cell_width);
|
padding_x = dynamic_padding(padding_x, viewport_size.width as f32, cell_width);
|
||||||
padding_y = dynamic_padding(padding_y, viewport_size.height as f32, cell_height);
|
padding_y = dynamic_padding(padding_y, viewport_size.height as f32, cell_height);
|
||||||
}
|
}
|
||||||
|
@ -180,7 +205,7 @@ impl Display {
|
||||||
info!("Cell Size: {} x {}", cell_width, cell_height);
|
info!("Cell Size: {} x {}", cell_width, cell_height);
|
||||||
info!("Padding: {} x {}", padding_x, padding_y);
|
info!("Padding: {} x {}", padding_x, padding_y);
|
||||||
|
|
||||||
// Create new size with at least one column and row
|
// Create new size with at least one column and row.
|
||||||
let size_info = SizeInfo {
|
let size_info = SizeInfo {
|
||||||
dpr,
|
dpr,
|
||||||
width: (viewport_size.width as f32).max(cell_width + 2. * padding_x),
|
width: (viewport_size.width as f32).max(cell_width + 2. * padding_x),
|
||||||
|
@ -191,10 +216,10 @@ impl Display {
|
||||||
padding_y,
|
padding_y,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update OpenGL projection
|
// Update OpenGL projection.
|
||||||
renderer.resize(&size_info);
|
renderer.resize(&size_info);
|
||||||
|
|
||||||
// Clear screen
|
// Call `clear` before showing the window, to make sure the surface is initialized.
|
||||||
let background_color = config.colors.primary.background;
|
let background_color = config.colors.primary.background;
|
||||||
renderer.with_api(&config, &size_info, |api| {
|
renderer.with_api(&config, &size_info, |api| {
|
||||||
api.clear(background_color);
|
api.clear(background_color);
|
||||||
|
@ -203,12 +228,10 @@ impl Display {
|
||||||
#[cfg(not(any(target_os = "macos", windows)))]
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
let is_x11 = event_loop.is_x11();
|
let is_x11 = event_loop.is_x11();
|
||||||
|
|
||||||
// We should call `clear` when window is offscreen, so when `window.show()` happens it
|
|
||||||
// would be with background color instead of uninitialized surface.
|
|
||||||
#[cfg(not(any(target_os = "macos", windows)))]
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
{
|
{
|
||||||
// On Wayland we can safely ignore this call, since the window isn't visible until you
|
// On Wayland we can safely ignore this call, since the window isn't visible until you
|
||||||
// actually draw something into it.
|
// actually draw something into it and commit those changes.
|
||||||
if is_x11 {
|
if is_x11 {
|
||||||
window.swap_buffers();
|
window.swap_buffers();
|
||||||
renderer.with_api(&config, &size_info, |api| {
|
renderer.with_api(&config, &size_info, |api| {
|
||||||
|
@ -219,10 +242,10 @@ impl Display {
|
||||||
|
|
||||||
window.set_visible(true);
|
window.set_visible(true);
|
||||||
|
|
||||||
// Set window position
|
// Set window position.
|
||||||
//
|
//
|
||||||
// TODO: replace `set_position` with `with_position` once available
|
// TODO: replace `set_position` with `with_position` once available
|
||||||
// Upstream issue: https://github.com/rust-windowing/winit/issues/806
|
// Upstream issue: https://github.com/rust-windowing/winit/issues/806.
|
||||||
if let Some(position) = config.window.position {
|
if let Some(position) = config.window.position {
|
||||||
window.set_outer_position(PhysicalPosition::from((position.x, position.y)));
|
window.set_outer_position(PhysicalPosition::from((position.x, position.y)));
|
||||||
}
|
}
|
||||||
|
@ -247,6 +270,8 @@ impl Display {
|
||||||
highlighted_url: None,
|
highlighted_url: None,
|
||||||
#[cfg(not(any(target_os = "macos", windows)))]
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
is_x11,
|
is_x11,
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
wayland_event_queue,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -258,7 +283,7 @@ impl Display {
|
||||||
let font = config.font.clone();
|
let font = config.font.clone();
|
||||||
let rasterizer = font::Rasterizer::new(dpr as f32, config.font.use_thin_strokes())?;
|
let rasterizer = font::Rasterizer::new(dpr as f32, config.font.use_thin_strokes())?;
|
||||||
|
|
||||||
// Initialize glyph cache
|
// Initialize glyph cache.
|
||||||
let glyph_cache = {
|
let glyph_cache = {
|
||||||
info!("Initializing glyph cache...");
|
info!("Initializing glyph cache...");
|
||||||
let init_start = Instant::now();
|
let init_start = Instant::now();
|
||||||
|
@ -281,7 +306,7 @@ impl Display {
|
||||||
Ok((glyph_cache, cw, ch))
|
Ok((glyph_cache, cw, ch))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update font size and cell dimensions
|
/// Update font size and cell dimensions.
|
||||||
fn update_glyph_cache(&mut self, config: &Config, font: Font) {
|
fn update_glyph_cache(&mut self, config: &Config, font: Font) {
|
||||||
let size_info = &mut self.size_info;
|
let size_info = &mut self.size_info;
|
||||||
let cache = &mut self.glyph_cache;
|
let cache = &mut self.glyph_cache;
|
||||||
|
@ -290,7 +315,7 @@ impl Display {
|
||||||
let _ = cache.update_font_size(font, size_info.dpr, &mut api);
|
let _ = cache.update_font_size(font, size_info.dpr, &mut api);
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update cell size
|
// Update cell size.
|
||||||
let (cell_width, cell_height) = compute_cell_size(config, &self.glyph_cache.font_metrics());
|
let (cell_width, cell_height) = compute_cell_size(config, &self.glyph_cache.font_metrics());
|
||||||
size_info.cell_width = cell_width;
|
size_info.cell_width = cell_width;
|
||||||
size_info.cell_height = cell_height;
|
size_info.cell_height = cell_height;
|
||||||
|
@ -313,7 +338,7 @@ impl Display {
|
||||||
config: &Config,
|
config: &Config,
|
||||||
update_pending: DisplayUpdate,
|
update_pending: DisplayUpdate,
|
||||||
) {
|
) {
|
||||||
// Update font size and cell dimensions
|
// Update font size and cell dimensions.
|
||||||
if let Some(font) = update_pending.font {
|
if let Some(font) = update_pending.font {
|
||||||
self.update_glyph_cache(config, font);
|
self.update_glyph_cache(config, font);
|
||||||
} else if update_pending.cursor {
|
} else if update_pending.cursor {
|
||||||
|
@ -323,18 +348,18 @@ impl Display {
|
||||||
let cell_width = self.size_info.cell_width;
|
let cell_width = self.size_info.cell_width;
|
||||||
let cell_height = self.size_info.cell_height;
|
let cell_height = self.size_info.cell_height;
|
||||||
|
|
||||||
// Recalculate padding
|
// Recalculate padding.
|
||||||
let mut padding_x = f32::from(config.window.padding.x) * self.size_info.dpr as f32;
|
let mut padding_x = f32::from(config.window.padding.x) * self.size_info.dpr as f32;
|
||||||
let mut padding_y = f32::from(config.window.padding.y) * self.size_info.dpr as f32;
|
let mut padding_y = f32::from(config.window.padding.y) * self.size_info.dpr as f32;
|
||||||
|
|
||||||
// Update the window dimensions
|
// Update the window dimensions.
|
||||||
if let Some(size) = update_pending.dimensions {
|
if let Some(size) = update_pending.dimensions {
|
||||||
// Ensure we have at least one column and row
|
// Ensure we have at least one column and row.
|
||||||
self.size_info.width = (size.width as f32).max(cell_width + 2. * padding_x);
|
self.size_info.width = (size.width as f32).max(cell_width + 2. * padding_x);
|
||||||
self.size_info.height = (size.height as f32).max(cell_height + 2. * padding_y);
|
self.size_info.height = (size.height as f32).max(cell_height + 2. * padding_y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Distribute excess padding equally on all sides
|
// Distribute excess padding equally on all sides.
|
||||||
if config.window.dynamic_padding {
|
if config.window.dynamic_padding {
|
||||||
padding_x = dynamic_padding(padding_x, self.size_info.width, cell_width);
|
padding_x = dynamic_padding(padding_x, self.size_info.width, cell_width);
|
||||||
padding_y = dynamic_padding(padding_y, self.size_info.height, cell_height);
|
padding_y = dynamic_padding(padding_y, self.size_info.height, cell_height);
|
||||||
|
@ -345,29 +370,29 @@ impl Display {
|
||||||
|
|
||||||
let mut pty_size = self.size_info;
|
let mut pty_size = self.size_info;
|
||||||
|
|
||||||
// Subtract message bar lines from pty size
|
// Subtract message bar lines from pty size.
|
||||||
if let Some(message) = message_buffer.message() {
|
if let Some(message) = message_buffer.message() {
|
||||||
let lines = message.text(&self.size_info).len();
|
let lines = message.text(&self.size_info).len();
|
||||||
pty_size.height -= pty_size.cell_height * lines as f32;
|
pty_size.height -= pty_size.cell_height * lines as f32;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resize PTY
|
// Resize PTY.
|
||||||
pty_resize_handle.on_resize(&pty_size);
|
pty_resize_handle.on_resize(&pty_size);
|
||||||
|
|
||||||
// Resize terminal
|
// Resize terminal.
|
||||||
terminal.resize(&pty_size);
|
terminal.resize(&pty_size);
|
||||||
|
|
||||||
// Resize renderer
|
// Resize renderer.
|
||||||
let physical = PhysicalSize::new(self.size_info.width as u32, self.size_info.height as u32);
|
let physical = PhysicalSize::new(self.size_info.width as u32, self.size_info.height as u32);
|
||||||
self.window.resize(physical);
|
self.window.resize(physical);
|
||||||
self.renderer.resize(&self.size_info);
|
self.renderer.resize(&self.size_info);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draw the screen
|
/// Draw the screen.
|
||||||
///
|
///
|
||||||
/// A reference to Term whose state is being drawn must be provided.
|
/// A reference to Term whose state is being drawn must be provided.
|
||||||
///
|
///
|
||||||
/// This call may block if vsync is enabled
|
/// This call may block if vsync is enabled.
|
||||||
pub fn draw<T>(
|
pub fn draw<T>(
|
||||||
&mut self,
|
&mut self,
|
||||||
terminal: MutexGuard<'_, Term<T>>,
|
terminal: MutexGuard<'_, Term<T>>,
|
||||||
|
@ -393,11 +418,11 @@ impl Display {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
// Update IME position
|
// Update IME position.
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
self.window.update_ime_position(&terminal, &self.size_info);
|
self.window.update_ime_position(&terminal, &self.size_info);
|
||||||
|
|
||||||
// Drop terminal as early as possible to free lock
|
// Drop terminal as early as possible to free lock.
|
||||||
drop(terminal);
|
drop(terminal);
|
||||||
|
|
||||||
self.renderer.with_api(&config, &size_info, |api| {
|
self.renderer.with_api(&config, &size_info, |api| {
|
||||||
|
@ -407,20 +432,20 @@ impl Display {
|
||||||
let mut lines = RenderLines::new();
|
let mut lines = RenderLines::new();
|
||||||
let mut urls = Urls::new();
|
let mut urls = Urls::new();
|
||||||
|
|
||||||
// Draw grid
|
// Draw grid.
|
||||||
{
|
{
|
||||||
let _sampler = self.meter.sampler();
|
let _sampler = self.meter.sampler();
|
||||||
|
|
||||||
self.renderer.with_api(&config, &size_info, |mut api| {
|
self.renderer.with_api(&config, &size_info, |mut api| {
|
||||||
// Iterate over all non-empty cells in the grid
|
// Iterate over all non-empty cells in the grid.
|
||||||
for cell in grid_cells {
|
for cell in grid_cells {
|
||||||
// Update URL underlines
|
// Update URL underlines.
|
||||||
urls.update(size_info.cols().0, cell);
|
urls.update(size_info.cols().0, cell);
|
||||||
|
|
||||||
// Update underline/strikeout
|
// Update underline/strikeout.
|
||||||
lines.update(cell);
|
lines.update(cell);
|
||||||
|
|
||||||
// Draw the cell
|
// Draw the cell.
|
||||||
api.render_cell(cell, glyph_cache);
|
api.render_cell(cell, glyph_cache);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -428,7 +453,7 @@ impl Display {
|
||||||
|
|
||||||
let mut rects = lines.rects(&metrics, &size_info);
|
let mut rects = lines.rects(&metrics, &size_info);
|
||||||
|
|
||||||
// Update visible URLs
|
// Update visible URLs.
|
||||||
self.urls = urls;
|
self.urls = urls;
|
||||||
if let Some(url) = self.urls.highlighted(config, mouse, mods, mouse_mode, selection) {
|
if let Some(url) = self.urls.highlighted(config, mouse, mods, mouse_mode, selection) {
|
||||||
rects.append(&mut url.rects(&metrics, &size_info));
|
rects.append(&mut url.rects(&metrics, &size_info));
|
||||||
|
@ -446,14 +471,14 @@ impl Display {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Highlight URLs at the vi mode cursor position
|
// Highlight URLs at the vi mode cursor position.
|
||||||
if let Some(vi_mode_cursor) = vi_mode_cursor {
|
if let Some(vi_mode_cursor) = vi_mode_cursor {
|
||||||
if let Some(url) = self.urls.find_at(vi_mode_cursor.point) {
|
if let Some(url) = self.urls.find_at(vi_mode_cursor.point) {
|
||||||
rects.append(&mut url.rects(&metrics, &size_info));
|
rects.append(&mut url.rects(&metrics, &size_info));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Push visual bell after url/underline/strikeout rects
|
// Push visual bell after url/underline/strikeout rects.
|
||||||
if visual_bell_intensity != 0. {
|
if visual_bell_intensity != 0. {
|
||||||
let visual_bell_rect = RenderRect::new(
|
let visual_bell_rect = RenderRect::new(
|
||||||
0.,
|
0.,
|
||||||
|
@ -469,19 +494,19 @@ impl Display {
|
||||||
if let Some(message) = message_buffer.message() {
|
if let Some(message) = message_buffer.message() {
|
||||||
let text = message.text(&size_info);
|
let text = message.text(&size_info);
|
||||||
|
|
||||||
// Create a new rectangle for the background
|
// Create a new rectangle for the background.
|
||||||
let start_line = size_info.lines().0 - text.len();
|
let start_line = size_info.lines().0 - text.len();
|
||||||
let y = size_info.cell_height.mul_add(start_line as f32, size_info.padding_y);
|
let y = size_info.cell_height.mul_add(start_line as f32, size_info.padding_y);
|
||||||
let message_bar_rect =
|
let message_bar_rect =
|
||||||
RenderRect::new(0., y, size_info.width, size_info.height - y, message.color(), 1.);
|
RenderRect::new(0., y, size_info.width, size_info.height - y, message.color(), 1.);
|
||||||
|
|
||||||
// Push message_bar in the end, so it'll be above all other content
|
// Push message_bar in the end, so it'll be above all other content.
|
||||||
rects.push(message_bar_rect);
|
rects.push(message_bar_rect);
|
||||||
|
|
||||||
// Draw rectangles
|
// Draw rectangles.
|
||||||
self.renderer.draw_rects(&size_info, rects);
|
self.renderer.draw_rects(&size_info, rects);
|
||||||
|
|
||||||
// Relay messages to the user
|
// Relay messages to the user.
|
||||||
let mut offset = 1;
|
let mut offset = 1;
|
||||||
for message_text in text.iter().rev() {
|
for message_text in text.iter().rev() {
|
||||||
self.renderer.with_api(&config, &size_info, |mut api| {
|
self.renderer.with_api(&config, &size_info, |mut api| {
|
||||||
|
@ -495,11 +520,11 @@ impl Display {
|
||||||
offset += 1;
|
offset += 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Draw rectangles
|
// Draw rectangles.
|
||||||
self.renderer.draw_rects(&size_info, rects);
|
self.renderer.draw_rects(&size_info, rects);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw render timer
|
// Draw render timer.
|
||||||
if config.render_timer() {
|
if config.render_timer() {
|
||||||
let timing = format!("{:.3} usec", self.meter.average());
|
let timing = format!("{:.3} usec", self.meter.average());
|
||||||
let color = Rgb { r: 0xd5, g: 0x4e, b: 0x53 };
|
let color = Rgb { r: 0xd5, g: 0x4e, b: 0x53 };
|
||||||
|
@ -508,6 +533,11 @@ impl Display {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Frame event should be requested before swaping buffers, since it requires surface
|
||||||
|
// `commit`, which is done by swap buffers under the hood.
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
self.request_frame(&self.window);
|
||||||
|
|
||||||
self.window.swap_buffers();
|
self.window.swap_buffers();
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "macos", windows)))]
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
@ -522,9 +552,29 @@ impl Display {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Requst a new frame for a window on Wayland.
|
||||||
|
#[inline]
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
fn request_frame(&self, window: &Window) {
|
||||||
|
let surface = match window.wayland_surface() {
|
||||||
|
Some(surface) => surface,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let should_draw = self.window.should_draw.clone();
|
||||||
|
|
||||||
|
// Mark that window was drawn.
|
||||||
|
should_draw.store(false, Ordering::Relaxed);
|
||||||
|
|
||||||
|
// Request a new frame.
|
||||||
|
surface.frame().quick_assign(move |_, _, _| {
|
||||||
|
should_draw.store(true, Ordering::Relaxed);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate padding to spread it evenly around the terminal content
|
/// Calculate padding to spread it evenly around the terminal content.
|
||||||
#[inline]
|
#[inline]
|
||||||
fn dynamic_padding(padding: f32, dimension: f32, cell_dimension: f32) -> f32 {
|
fn dynamic_padding(padding: f32, dimension: f32, cell_dimension: f32) -> f32 {
|
||||||
padding + ((dimension - 2. * padding) % cell_dimension) / 2.
|
padding + ((dimension - 2. * padding) % cell_dimension) / 2.
|
||||||
|
|
|
@ -8,6 +8,8 @@ use std::fs::File;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
use std::sync::atomic::Ordering;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::Instant;
|
use std::time::Instant;
|
||||||
|
|
||||||
|
@ -358,6 +360,7 @@ pub struct Processor<N> {
|
||||||
message_buffer: MessageBuffer,
|
message_buffer: MessageBuffer,
|
||||||
display: Display,
|
display: Display,
|
||||||
font_size: Size,
|
font_size: Size,
|
||||||
|
event_queue: Vec<GlutinEvent<'static, alacritty_terminal::event::Event>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: Notify + OnResize> Processor<N> {
|
impl<N: Notify + OnResize> Processor<N> {
|
||||||
|
@ -381,41 +384,65 @@ impl<N: Notify + OnResize> Processor<N> {
|
||||||
config,
|
config,
|
||||||
message_buffer,
|
message_buffer,
|
||||||
display,
|
display,
|
||||||
|
event_queue: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return `true` if `event_queue` is empty, `false` otherwise.
|
||||||
|
#[inline]
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
fn event_queue_empty(&mut self) -> bool {
|
||||||
|
let wayland_event_queue = match self.display.wayland_event_queue.as_mut() {
|
||||||
|
Some(wayland_event_queue) => wayland_event_queue,
|
||||||
|
// Since frame callbacks do not exist on X11, just check for event queue.
|
||||||
|
None => return self.event_queue.is_empty(),
|
||||||
|
};
|
||||||
|
|
||||||
|
// Check for pending frame callbacks on Wayland.
|
||||||
|
let events_dispatched = wayland_event_queue
|
||||||
|
.dispatch_pending(&mut (), |_, _, _| {})
|
||||||
|
.expect("failed to dispatch event queue");
|
||||||
|
|
||||||
|
self.event_queue.is_empty() && events_dispatched == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return `true` if `event_queue` is empty, `false` otherwise.
|
||||||
|
#[inline]
|
||||||
|
#[cfg(any(target_os = "macos", windows))]
|
||||||
|
fn event_queue_empty(&mut self) -> bool {
|
||||||
|
self.event_queue.is_empty()
|
||||||
|
}
|
||||||
|
|
||||||
/// Run the event loop.
|
/// Run the event loop.
|
||||||
pub fn run<T>(&mut self, terminal: Arc<FairMutex<Term<T>>>, mut event_loop: EventLoop<Event>)
|
pub fn run<T>(&mut self, terminal: Arc<FairMutex<Term<T>>>, mut event_loop: EventLoop<Event>)
|
||||||
where
|
where
|
||||||
T: EventListener,
|
T: EventListener,
|
||||||
{
|
{
|
||||||
let mut event_queue = Vec::new();
|
|
||||||
|
|
||||||
event_loop.run_return(|event, event_loop, control_flow| {
|
event_loop.run_return(|event, event_loop, control_flow| {
|
||||||
if self.config.debug.print_events {
|
if self.config.debug.print_events {
|
||||||
info!("glutin event: {:?}", event);
|
info!("glutin event: {:?}", event);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ignore all events we do not care about
|
// Ignore all events we do not care about.
|
||||||
if Self::skip_event(&event) {
|
if Self::skip_event(&event) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
// Check for shutdown
|
// Check for shutdown.
|
||||||
GlutinEvent::UserEvent(Event::Exit) => {
|
GlutinEvent::UserEvent(Event::Exit) => {
|
||||||
*control_flow = ControlFlow::Exit;
|
*control_flow = ControlFlow::Exit;
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
// Process events
|
// Process events.
|
||||||
GlutinEvent::RedrawEventsCleared => {
|
GlutinEvent::RedrawEventsCleared => {
|
||||||
*control_flow = ControlFlow::Wait;
|
*control_flow = ControlFlow::Wait;
|
||||||
|
|
||||||
if event_queue.is_empty() {
|
if self.event_queue_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// Remap DPR change event to remove lifetime
|
// Remap DPR change event to remove lifetime.
|
||||||
GlutinEvent::WindowEvent {
|
GlutinEvent::WindowEvent {
|
||||||
event: WindowEvent::ScaleFactorChanged { scale_factor, new_inner_size },
|
event: WindowEvent::ScaleFactorChanged { scale_factor, new_inner_size },
|
||||||
..
|
..
|
||||||
|
@ -423,14 +450,14 @@ impl<N: Notify + OnResize> Processor<N> {
|
||||||
*control_flow = ControlFlow::Poll;
|
*control_flow = ControlFlow::Poll;
|
||||||
let size = (new_inner_size.width, new_inner_size.height);
|
let size = (new_inner_size.width, new_inner_size.height);
|
||||||
let event = GlutinEvent::UserEvent(Event::DPRChanged(scale_factor, size));
|
let event = GlutinEvent::UserEvent(Event::DPRChanged(scale_factor, size));
|
||||||
event_queue.push(event);
|
self.event_queue.push(event);
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
// Transmute to extend lifetime, which exists only for `ScaleFactorChanged` event.
|
// Transmute to extend lifetime, which exists only for `ScaleFactorChanged` event.
|
||||||
// Since we remap that event to remove the lifetime, this is safe.
|
// Since we remap that event to remove the lifetime, this is safe.
|
||||||
event => unsafe {
|
event => unsafe {
|
||||||
*control_flow = ControlFlow::Poll;
|
*control_flow = ControlFlow::Poll;
|
||||||
event_queue.push(mem::transmute(event));
|
self.event_queue.push(mem::transmute(event));
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -457,11 +484,11 @@ impl<N: Notify + OnResize> Processor<N> {
|
||||||
};
|
};
|
||||||
let mut processor = input::Processor::new(context, &self.display.highlighted_url);
|
let mut processor = input::Processor::new(context, &self.display.highlighted_url);
|
||||||
|
|
||||||
for event in event_queue.drain(..) {
|
for event in self.event_queue.drain(..) {
|
||||||
Processor::handle_event(event, &mut processor);
|
Processor::handle_event(event, &mut processor);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process DisplayUpdate events
|
// Process DisplayUpdate events.
|
||||||
if !display_update_pending.is_empty() {
|
if !display_update_pending.is_empty() {
|
||||||
self.display.handle_update(
|
self.display.handle_update(
|
||||||
&mut terminal,
|
&mut terminal,
|
||||||
|
@ -472,15 +499,25 @@ impl<N: Notify + OnResize> Processor<N> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
{
|
||||||
|
// Skip rendering on Wayland until we get frame event from compositor.
|
||||||
|
if event_loop.is_wayland()
|
||||||
|
&& !self.display.window.should_draw.load(Ordering::Relaxed)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if terminal.dirty {
|
if terminal.dirty {
|
||||||
terminal.dirty = false;
|
terminal.dirty = false;
|
||||||
|
|
||||||
// Request immediate re-draw if visual bell animation is not finished yet
|
// Request immediate re-draw if visual bell animation is not finished yet.
|
||||||
if !terminal.visual_bell.completed() {
|
if !terminal.visual_bell.completed() {
|
||||||
event_queue.push(GlutinEvent::UserEvent(Event::Wakeup));
|
self.event_queue.push(GlutinEvent::UserEvent(Event::Wakeup));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redraw screen
|
// Redraw screen.
|
||||||
self.display.draw(
|
self.display.draw(
|
||||||
terminal,
|
terminal,
|
||||||
&self.message_buffer,
|
&self.message_buffer,
|
||||||
|
|
|
@ -17,6 +17,10 @@ use std::ffi::c_void;
|
||||||
use std::fmt::{self, Display, Formatter};
|
use std::fmt::{self, Display, Formatter};
|
||||||
#[cfg(not(any(target_os = "macos", windows)))]
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
use std::os::raw::c_ulong;
|
use std::os::raw::c_ulong;
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
use std::sync::atomic::AtomicBool;
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use glutin::dpi::{PhysicalPosition, PhysicalSize};
|
use glutin::dpi::{PhysicalPosition, PhysicalSize};
|
||||||
use glutin::event_loop::EventLoop;
|
use glutin::event_loop::EventLoop;
|
||||||
|
@ -51,6 +55,12 @@ use crate::gl;
|
||||||
#[cfg(not(any(target_os = "macos", windows)))]
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
use crate::wayland_theme::AlacrittyWaylandTheme;
|
use crate::wayland_theme::AlacrittyWaylandTheme;
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
use wayland_client::{Attached, EventQueue, Proxy};
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
use wayland_client::protocol::wl_surface::WlSurface;
|
||||||
|
|
||||||
// It's required to be in this directory due to the `windows.rc` file
|
// It's required to be in this directory due to the `windows.rc` file
|
||||||
#[cfg(not(any(target_os = "macos", windows)))]
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
static WINDOW_ICON: &[u8] = include_bytes!("../../extra/windows/alacritty.ico");
|
static WINDOW_ICON: &[u8] = include_bytes!("../../extra/windows/alacritty.ico");
|
||||||
|
@ -117,6 +127,7 @@ fn create_gl_window(
|
||||||
mut window: WindowBuilder,
|
mut window: WindowBuilder,
|
||||||
event_loop: &EventLoop<Event>,
|
event_loop: &EventLoop<Event>,
|
||||||
srgb: bool,
|
srgb: bool,
|
||||||
|
vsync: bool,
|
||||||
dimensions: Option<PhysicalSize<u32>>,
|
dimensions: Option<PhysicalSize<u32>>,
|
||||||
) -> Result<WindowedContext<PossiblyCurrent>> {
|
) -> Result<WindowedContext<PossiblyCurrent>> {
|
||||||
if let Some(dimensions) = dimensions {
|
if let Some(dimensions) = dimensions {
|
||||||
|
@ -125,7 +136,7 @@ fn create_gl_window(
|
||||||
|
|
||||||
let windowed_context = ContextBuilder::new()
|
let windowed_context = ContextBuilder::new()
|
||||||
.with_srgb(srgb)
|
.with_srgb(srgb)
|
||||||
.with_vsync(true)
|
.with_vsync(vsync)
|
||||||
.with_hardware_acceleration(None)
|
.with_hardware_acceleration(None)
|
||||||
.build_windowed(window, event_loop)?;
|
.build_windowed(window, event_loop)?;
|
||||||
|
|
||||||
|
@ -135,10 +146,18 @@ fn create_gl_window(
|
||||||
Ok(windowed_context)
|
Ok(windowed_context)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A window which can be used for displaying the terminal
|
/// A window which can be used for displaying the terminal.
|
||||||
///
|
///
|
||||||
/// Wraps the underlying windowing library to provide a stable API in Alacritty
|
/// Wraps the underlying windowing library to provide a stable API in Alacritty.
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
|
/// Flag tracking frame redraw requests from Wayland compositor.
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
pub should_draw: Arc<AtomicBool>,
|
||||||
|
|
||||||
|
/// Attached Wayland surface to request new frame events.
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
pub wayland_surface: Option<Attached<WlSurface>>,
|
||||||
|
|
||||||
windowed_context: WindowedContext<PossiblyCurrent>,
|
windowed_context: WindowedContext<PossiblyCurrent>,
|
||||||
current_mouse_cursor: CursorIcon,
|
current_mouse_cursor: CursorIcon,
|
||||||
mouse_visible: bool,
|
mouse_visible: bool,
|
||||||
|
@ -152,33 +171,58 @@ impl Window {
|
||||||
event_loop: &EventLoop<Event>,
|
event_loop: &EventLoop<Event>,
|
||||||
config: &Config,
|
config: &Config,
|
||||||
size: Option<PhysicalSize<u32>>,
|
size: Option<PhysicalSize<u32>>,
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))] wayland_event_queue: Option<&EventQueue>,
|
||||||
) -> Result<Window> {
|
) -> Result<Window> {
|
||||||
let window_builder = Window::get_platform_window(&config.window.title, &config.window);
|
let window_builder = Window::get_platform_window(&config.window.title, &config.window);
|
||||||
let windowed_context =
|
|
||||||
create_gl_window(window_builder.clone(), &event_loop, false, size)
|
|
||||||
.or_else(|_| create_gl_window(window_builder, &event_loop, true, size))?;
|
|
||||||
|
|
||||||
// Text cursor
|
// Disable vsync on Wayland.
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
let vsync = !event_loop.is_wayland();
|
||||||
|
#[cfg(any(target_os = "macos", windows))]
|
||||||
|
let vsync = true;
|
||||||
|
|
||||||
|
let windowed_context =
|
||||||
|
create_gl_window(window_builder.clone(), &event_loop, false, vsync, size)
|
||||||
|
.or_else(|_| create_gl_window(window_builder, &event_loop, true, vsync, size))?;
|
||||||
|
|
||||||
|
// Text cursor.
|
||||||
let current_mouse_cursor = CursorIcon::Text;
|
let current_mouse_cursor = CursorIcon::Text;
|
||||||
windowed_context.window().set_cursor_icon(current_mouse_cursor);
|
windowed_context.window().set_cursor_icon(current_mouse_cursor);
|
||||||
|
|
||||||
// Set OpenGL symbol loader. This call MUST be after window.make_current on windows.
|
// Set OpenGL symbol loader. This call MUST be after window.make_current on windows.
|
||||||
gl::load_with(|symbol| windowed_context.get_proc_address(symbol) as *const _);
|
gl::load_with(|symbol| windowed_context.get_proc_address(symbol) as *const _);
|
||||||
|
|
||||||
// On X11, embed the window inside another if the parent ID has been set
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
let mut wayland_surface = None;
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "macos", windows)))]
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
{
|
{
|
||||||
if event_loop.is_x11() {
|
if event_loop.is_x11() {
|
||||||
|
// On X11, embed the window inside another if the parent ID has been set.
|
||||||
if let Some(parent_window_id) = config.window.embed {
|
if let Some(parent_window_id) = config.window.embed {
|
||||||
x_embed_window(windowed_context.window(), parent_window_id);
|
x_embed_window(windowed_context.window(), parent_window_id);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Apply client side decorations theme.
|
||||||
let theme = AlacrittyWaylandTheme::new(&config.colors);
|
let theme = AlacrittyWaylandTheme::new(&config.colors);
|
||||||
windowed_context.window().set_wayland_theme(theme);
|
windowed_context.window().set_wayland_theme(theme);
|
||||||
|
|
||||||
|
// Attach surface to Alacritty's internal wayland queue to handle frame callbacks.
|
||||||
|
let surface = windowed_context.window().wayland_surface().unwrap();
|
||||||
|
let proxy: Proxy<WlSurface> = unsafe { Proxy::from_c_ptr(surface as _) };
|
||||||
|
wayland_surface = Some(proxy.attach(wayland_event_queue.as_ref().unwrap().token()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self { current_mouse_cursor, mouse_visible: true, windowed_context })
|
Ok(Self {
|
||||||
|
current_mouse_cursor,
|
||||||
|
mouse_visible: true,
|
||||||
|
windowed_context,
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
should_draw: Arc::new(AtomicBool::new(true)),
|
||||||
|
#[cfg(not(any(target_os = "macos", windows)))]
|
||||||
|
wayland_surface,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_inner_size(&mut self, size: PhysicalSize<u32>) {
|
pub fn set_inner_size(&mut self, size: PhysicalSize<u32>) {
|
||||||
|
@ -363,6 +407,11 @@ impl Window {
|
||||||
self.window().wayland_display()
|
self.window().wayland_display()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
|
||||||
|
pub fn wayland_surface(&self) -> Option<&Attached<WlSurface>> {
|
||||||
|
self.wayland_surface.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
|
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
|
||||||
pub fn set_wayland_theme(&mut self, colors: &Colors) {
|
pub fn set_wayland_theme(&mut self, colors: &Colors) {
|
||||||
self.window().set_wayland_theme(AlacrittyWaylandTheme::new(colors));
|
self.window().set_wayland_theme(AlacrittyWaylandTheme::new(colors));
|
||||||
|
|
Loading…
Reference in New Issue