aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Duerr <contact@christianduerr.com>2019-10-05 02:29:26 +0200
committerGitHub <noreply@github.com>2019-10-05 02:29:26 +0200
commit729eef0c933831bccfeac6a355bdb410787fbe5f (patch)
tree35cdf2e6427ad18bc53efbab4cab34a0af2054d7
parentb0c6fdff763f7271506d26d7e768e6377fdc691b (diff)
downloadalacritty-729eef0c933831bccfeac6a355bdb410787fbe5f.tar.gz
alacritty-729eef0c933831bccfeac6a355bdb410787fbe5f.zip
Update to winit/glutin EventLoop 2.0
This takes the latest glutin master to port Alacritty to the EventLoop 2.0 rework. This changes a big part of the event loop handling by pushing the event loop in a separate thread from the renderer and running both in parallel. Fixes #2796. Fixes #2694. Fixes #2643. Fixes #2625. Fixes #2618. Fixes #2601. Fixes #2564. Fixes #2456. Fixes #2438. Fixes #2334. Fixes #2254. Fixes #2217. Fixes #1789. Fixes #1750. Fixes #1125.
-rw-r--r--CHANGELOG.md13
-rw-r--r--Cargo.lock455
-rw-r--r--alacritty/Cargo.toml14
-rw-r--r--alacritty/src/cli.rs8
-rw-r--r--alacritty/src/config/bindings.rs (renamed from alacritty_terminal/src/config/bindings.rs)402
-rw-r--r--alacritty/src/config/mod.rs (renamed from alacritty/src/config.rs)27
-rw-r--r--alacritty/src/config/monitor.rs (renamed from alacritty_terminal/src/config/monitor.rs)37
-rw-r--r--alacritty/src/config/mouse.rs (renamed from alacritty_terminal/src/config/mouse.rs)15
-rw-r--r--alacritty/src/config/test.rs (renamed from alacritty_terminal/src/config/test.rs)8
-rw-r--r--alacritty/src/config/ui_config.rs63
-rw-r--r--alacritty/src/display.rs476
-rw-r--r--alacritty/src/event.rs651
-rw-r--r--alacritty/src/input.rs (renamed from alacritty_terminal/src/input.rs)765
-rw-r--r--alacritty/src/logging.rs22
-rw-r--r--alacritty/src/main.rs182
-rw-r--r--alacritty/src/window.rs (renamed from alacritty_terminal/src/window.rs)319
-rw-r--r--alacritty_terminal/Cargo.toml11
-rw-r--r--alacritty_terminal/src/ansi.rs17
-rw-r--r--alacritty_terminal/src/clipboard.rs2
-rw-r--r--alacritty_terminal/src/config/colors.rs18
-rw-r--r--alacritty_terminal/src/config/debug.rs11
-rw-r--r--alacritty_terminal/src/config/font.rs10
-rw-r--r--alacritty_terminal/src/config/mod.rs86
-rw-r--r--alacritty_terminal/src/config/scrolling.rs12
-rw-r--r--alacritty_terminal/src/config/visual_bell.rs4
-rw-r--r--alacritty_terminal/src/config/window.rs6
-rw-r--r--alacritty_terminal/src/cursor.rs2
-rw-r--r--alacritty_terminal/src/display.rs603
-rw-r--r--alacritty_terminal/src/event.rs561
-rw-r--r--alacritty_terminal/src/event_loop.rs103
-rw-r--r--alacritty_terminal/src/grid/mod.rs2
-rw-r--r--alacritty_terminal/src/grid/row.rs2
-rw-r--r--alacritty_terminal/src/grid/storage.rs1
-rw-r--r--alacritty_terminal/src/index.rs6
-rw-r--r--alacritty_terminal/src/lib.rs12
-rw-r--r--alacritty_terminal/src/macros.rs21
-rw-r--r--alacritty_terminal/src/message_bar.rs148
-rw-r--r--alacritty_terminal/src/meter.rs1
-rw-r--r--alacritty_terminal/src/renderer/mod.rs122
-rw-r--r--alacritty_terminal/src/renderer/rects.rs2
-rw-r--r--alacritty_terminal/src/selection.rs15
-rw-r--r--alacritty_terminal/src/term/cell.rs2
-rw-r--r--alacritty_terminal/src/term/color.rs3
-rw-r--r--alacritty_terminal/src/term/mod.rs398
-rw-r--r--alacritty_terminal/src/tty/mod.rs2
-rw-r--r--alacritty_terminal/src/tty/unix.rs38
-rw-r--r--alacritty_terminal/src/tty/windows/conpty.rs9
-rw-r--r--alacritty_terminal/src/tty/windows/mod.rs5
-rw-r--r--alacritty_terminal/src/tty/windows/winpty.rs8
-rw-r--r--alacritty_terminal/src/url.rs2
-rw-r--r--alacritty_terminal/tests/ref.rs16
-rw-r--r--font/src/darwin/mod.rs11
-rw-r--r--font/src/ft/mod.rs2
-rw-r--r--font/src/lib.rs31
54 files changed, 2743 insertions, 3019 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c2c5b274..b472f603 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -53,6 +53,19 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Discard scrolling region escape with bottom above top
- Opacity always applying to cells with their background color matching the teriminal background
- Allow semicolons when setting titles using an OSC
+- Background always opaque on X11
+- Skipping redraws on PTY update
+- Not redrawing while resizing on Windows/macOS
+- Decorations `none` launching an invisible window on Windows
+- Alacritty turning transparent when opening another window on macOS with chunkwm
+- Startup mode `Maximized` having no effect on Windows
+- Inserting Emojis using `Super+.` or compose sequences on Windows
+- Change mouse cursor depending on mode with Wayland
+- Hide mouse cursor when typing if the `mouse.hide_when_typing` option is set on Wayland
+- Glitches when DPI changes on Windows
+- Crash when resuming after suspension
+- Crash when trying to start on X11 with a Wayland compositor running
+- Crash with a virtual display connected on X11
### Removed
diff --git a/Cargo.lock b/Cargo.lock
index 6e258631..0aba11db 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,7 +2,7 @@
# It is not intended for manual editing.
[[package]]
name = "adler32"
-version = "1.0.3"
+version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -27,15 +27,23 @@ version = "0.3.3"
dependencies = [
"alacritty_terminal 0.3.3",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "font 0.1.0",
+ "glutin 0.22.0-alpha3 (git+https://github.com/chrisduerr/glutin)",
+ "image 0.21.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
+ "notify 4.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_tools_util 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-width 0.1.6 (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.4 (registry+https://github.com/rust-lang/crates.io-index)",
"xdg 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -44,15 +52,12 @@ name = "alacritty_terminal"
version = "0.3.3"
dependencies = [
"base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"copypasta 0.6.0",
- "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
"dunce 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
"font 0.1.0",
"gl_generator 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "glutin 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "image 0.21.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -65,9 +70,8 @@ dependencies = [
"objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rfind_url 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)",
"signal-hook 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"static_assertions 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -78,7 +82,6 @@ dependencies = [
"widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
"winpty 0.1.0",
- "x11-dl 2.18.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -86,7 +89,7 @@ name = "andrew"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"line_drawing 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rusttype 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)",
"walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -117,7 +120,7 @@ dependencies = [
[[package]]
name = "arc-swap"
-version = "0.4.2"
+version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -134,6 +137,11 @@ dependencies = [
]
[[package]]
+name = "arrayvec"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "atty"
version = "0.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -149,11 +157,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "backtrace"
-version = "0.3.37"
+version = "0.3.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -181,7 +189,7 @@ version = "0.33.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"clang-sys 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -195,7 +203,7 @@ dependencies = [
[[package]]
name = "bitflags"
-version = "1.1.0"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@@ -246,6 +254,16 @@ dependencies = [
]
[[package]]
+name = "calloop"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "cc"
version = "1.0.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -264,15 +282,14 @@ dependencies = [
[[package]]
name = "cfg-if"
-version = "0.1.9"
+version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "cgl"
-version = "0.2.3"
+version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "gleam 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -293,7 +310,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -313,7 +330,7 @@ name = "cloudabi"
version = "0.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -329,7 +346,7 @@ name = "cocoa"
version = "0.18.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -382,7 +399,7 @@ name = "core-graphics"
version = "0.17.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -400,19 +417,23 @@ dependencies = [
]
[[package]]
-name = "crc32fast"
-version = "1.2.0"
+name = "core-video-sys"
+version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
+ "objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "crossbeam-channel"
-version = "0.3.9"
+name = "crc32fast"
+version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -430,7 +451,7 @@ version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -450,7 +471,7 @@ name = "crossbeam-utils"
version = "0.6.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -459,21 +480,11 @@ name = "deflate"
version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
-name = "derivative"
-version = "1.0.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
name = "dirs"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -484,6 +495,11 @@ dependencies = [
]
[[package]]
+name = "dispatch"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "dlib"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -513,23 +529,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde_derive 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "either"
-version = "1.5.2"
+version = "1.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "embed-resource"
-version = "1.3.0"
+version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"vswhom 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "winreg 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -538,7 +554,7 @@ version = "0.5.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -550,7 +566,7 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -578,7 +594,7 @@ name = "failure"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)",
+ "backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)",
"failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -598,7 +614,7 @@ name = "filetime"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -606,9 +622,10 @@ dependencies = [
[[package]]
name = "flate2"
-version = "1.0.11"
+version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"miniz_oxide 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -658,7 +675,7 @@ name = "foreign-types-macros"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -678,7 +695,7 @@ name = "freetype-rs"
version = "0.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"freetype-sys 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -698,7 +715,7 @@ name = "fsevent"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -720,7 +737,7 @@ name = "fuchsia-zircon"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -734,14 +751,14 @@ name = "getrandom"
version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "gif"
-version = "0.10.2"
+version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"color_quant 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -750,16 +767,6 @@ dependencies = [
[[package]]
name = "gl_generator"
-version = "0.11.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "khronos_api 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "gl_generator"
version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
@@ -769,82 +776,74 @@ dependencies = [
]
[[package]]
-name = "gleam"
-version = "0.6.19"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "gl_generator 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
name = "glob"
version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "glutin"
-version = "0.21.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
+version = "0.22.0-alpha3"
+source = "git+https://github.com/chrisduerr/glutin#89aed1cbfe38532c15d073e3b0822362cab3e044"
dependencies = [
"android_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "cgl 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cgl 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "derivative 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "glutin_egl_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "glutin_emscripten_sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "glutin_gles2_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "glutin_glx_sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
- "glutin_wgl_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "glutin_egl_sys 0.1.3 (git+https://github.com/chrisduerr/glutin)",
+ "glutin_emscripten_sys 0.1.0 (git+https://github.com/chrisduerr/glutin)",
+ "glutin_gles2_sys 0.1.3 (git+https://github.com/chrisduerr/glutin)",
+ "glutin_glx_sys 0.1.5 (git+https://github.com/chrisduerr/glutin)",
+ "glutin_wgl_sys 0.1.3 (git+https://github.com/chrisduerr/glutin)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libloading 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "wayland-client 0.21.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wayland-client 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "winit 0.19.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winit 0.20.0-alpha3 (git+https://github.com/rust-windowing/winit)",
]
[[package]]
name = "glutin_egl_sys"
version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
+source = "git+https://github.com/chrisduerr/glutin#89aed1cbfe38532c15d073e3b0822362cab3e044"
dependencies = [
- "gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gl_generator 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "glutin_emscripten_sys"
version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
+source = "git+https://github.com/chrisduerr/glutin#89aed1cbfe38532c15d073e3b0822362cab3e044"
[[package]]
name = "glutin_gles2_sys"
version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
+source = "git+https://github.com/chrisduerr/glutin#89aed1cbfe38532c15d073e3b0822362cab3e044"
dependencies = [
- "gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gl_generator 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
"objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "glutin_glx_sys"
version = "0.1.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
+source = "git+https://github.com/chrisduerr/glutin#89aed1cbfe38532c15d073e3b0822362cab3e044"
dependencies = [
- "gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gl_generator 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
"x11-dl 2.18.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "glutin_wgl_sys"
version = "0.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
+source = "git+https://github.com/chrisduerr/glutin#89aed1cbfe38532c15d073e3b0822362cab3e044"
dependencies = [
- "gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gl_generator 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -858,7 +857,7 @@ dependencies = [
[[package]]
name = "humantime"
-version = "1.2.0"
+version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -880,7 +879,7 @@ version = "0.21.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "gif 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "gif 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)",
"jpeg-decoder 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
"lzw 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -896,7 +895,7 @@ name = "inflate"
version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -904,7 +903,7 @@ name = "inotify"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1025,7 +1024,7 @@ name = "log"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1086,7 +1085,7 @@ name = "miniz_oxide"
version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1176,10 +1175,10 @@ dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl 0.10.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl 0.10.25 (registry+https://github.com/rust-lang/crates.io-index)",
"openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-sys 0.9.49 (registry+https://github.com/rust-lang/crates.io-index)",
- "schannel 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.50 (registry+https://github.com/rust-lang/crates.io-index)",
+ "schannel 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
"security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1190,7 +1189,7 @@ name = "net2"
version = "0.2.33"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1200,9 +1199,9 @@ name = "nix"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)",
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1234,7 +1233,7 @@ name = "notify"
version = "4.0.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
"fsevent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1330,15 +1329,15 @@ dependencies = [
[[package]]
name = "openssl"
-version = "0.10.24"
+version = "0.10.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
- "openssl-sys 0.9.49 (registry+https://github.com/rust-lang/crates.io-index)",
+ "openssl-sys 0.9.50 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1348,7 +1347,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "openssl-sys"
-version = "0.9.49"
+version = "0.9.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1389,7 +1388,7 @@ name = "parking_lot_core"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1452,7 +1451,7 @@ name = "png"
version = "0.14.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"deflate 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)",
"inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1478,7 +1477,7 @@ dependencies = [
[[package]]
name = "proc-macro2"
-version = "1.0.3"
+version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1507,7 +1506,7 @@ name = "quote"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1530,7 +1529,7 @@ dependencies = [
[[package]]
name = "rand"
-version = "0.7.0"
+version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1644,12 +1643,20 @@ dependencies = [
]
[[package]]
+name = "raw-window-handle"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
name = "rayon"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1771,16 +1778,16 @@ name = "rusttype"
version = "0.7.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "rusttype 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rusttype 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "rusttype"
-version = "0.8.0"
+version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "arrayvec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"stb_truetype 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1800,7 +1807,7 @@ dependencies = [
[[package]]
name = "schannel"
-version = "0.1.15"
+version = "0.1.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1851,27 +1858,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
-version = "1.0.100"
+version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
+]
[[package]]
name = "serde_derive"
-version = "1.0.100"
+version = "1.0.101"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_json"
-version = "1.0.40"
+version = "1.0.41"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@@ -1881,7 +1891,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
- "serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)",
+ "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
"yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1935,7 +1945,7 @@ name = "signal-hook-registry"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "arc-swap 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
+ "arc-swap 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -1956,27 +1966,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "smithay-client-toolkit"
-version = "0.4.6"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "andrew 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "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)",
- "memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "wayland-client 0.21.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "wayland-commons 0.21.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "wayland-protocols 0.21.13 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "smithay-client-toolkit"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"andrew 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
"memmap 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1999,7 +1993,7 @@ name = "socket2"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2043,7 +2037,7 @@ name = "syn"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -2064,9 +2058,9 @@ name = "tempfile"
version = "3.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
+ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
- "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
"redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
"remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2255,26 +2249,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "wayland-client"
-version = "0.21.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "downcast-rs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
- "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
- "nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "wayland-commons 0.21.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "wayland-scanner 0.21.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "wayland-sys 0.21.13 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "wayland-client"
version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "calloop 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"downcast-rs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
+ "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
"nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
"wayland-commons 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)",
"wayland-scanner 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2283,15 +2265,6 @@ dependencies = [
[[package]]
name = "wayland-commons"
-version = "0.21.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
- "wayland-sys 0.21.13 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "wayland-commons"
version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
@@ -2301,22 +2274,10 @@ dependencies = [
[[package]]
name = "wayland-protocols"
-version = "0.21.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "wayland-client 0.21.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "wayland-commons 0.21.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "wayland-scanner 0.21.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "wayland-sys 0.21.13 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "wayland-protocols"
version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"wayland-client 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)",
"wayland-commons 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)",
"wayland-scanner 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2324,16 +2285,6 @@ dependencies = [
[[package]]
name = "wayland-scanner"
-version = "0.21.13"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-dependencies = [
- "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)",
- "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)",
- "xml-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
-]
-
-[[package]]
-name = "wayland-scanner"
version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
@@ -2344,15 +2295,6 @@ dependencies = [
[[package]]
name = "wayland-sys"
-version = "0.21.13"
-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]]
-name = "wayland-sys"
version = "0.23.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
@@ -2421,24 +2363,26 @@ dependencies = [
[[package]]
name = "winit"
-version = "0.19.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
+version = "0.20.0-alpha3"
+source = "git+https://github.com/rust-windowing/winit#4f6ca8792cac0b006205c117fdf9c205a8240657"
dependencies = [
"android_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)",
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "calloop 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cocoa 0.18.4 (registry+https://github.com/rust-lang/crates.io-index)",
"core-foundation 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
"core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)",
- "image 0.21.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "core-video-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
+ "dispatch 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
"objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "smithay-client-toolkit 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
- "wayland-client 0.21.13 (registry+https://github.com/rust-lang/crates.io-index)",
+ "raw-window-handle 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "smithay-client-toolkit 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "wayland-client 0.23.6 (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.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
@@ -2447,8 +2391,8 @@ dependencies = [
name = "winpty"
version = "0.1.0"
dependencies = [
- "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "embed-resource 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "embed-resource 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"http_req 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
"named_pipe 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2469,7 +2413,7 @@ dependencies = [
[[package]]
name = "winreg"
-version = "0.5.1"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -2537,39 +2481,41 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bzip2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
- "flate2 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)",
"podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
]
[metadata]
-"checksum adler32 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7e522997b529f05601e05166c07ed17789691f562762c7f3b987263d2dedee5c"
+"checksum adler32 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2e7343e7fc9de883d1b0341e0b13970f764c14101234857d2ddafa1cb1cac2"
"checksum aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5"
"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
"checksum andrew 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9b7f09f89872c2b6b29e319377b1fbe91c6f5947df19a25596e121cf19a7b35e"
"checksum android_glue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "000444226fcff248f2bc4c7625be32c63caccfecc2723a2b9f78a7487a49c407"
"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
"checksum approx 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f0e60b75072ecd4168020818c0107f2857bb6c4e64252d8d3983f6263b40a5c3"
-"checksum arc-swap 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "854ede29f7a0ce90519fb2439d030320c6201119b87dab0ee96044603e1130b9"
+"checksum arc-swap 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f1a1eca3195b729bbd64e292ef2f5fff6b1c28504fed762ce2b1013dde4d8e92"
"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba"
+"checksum arrayvec 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ead801bcb8843bc91ea0a028f95b786f39ce519b1738de4e74a2a393332c2a16"
"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875"
-"checksum backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)" = "5180c5a20655b14a819b652fd2378fa5f1697b6c9ddad3e695c2f9cedf6df4e2"
+"checksum backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "690a62be8920ccf773ee00ef0968649b0e724cda8bd5b12286302b4ae955fdf5"
"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b"
"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
"checksum bindgen 0.33.2 (registry+https://github.com/rust-lang/crates.io-index)" = "603ed8d8392ace9581e834e26bd09799bf1e989a79bd1aedbb893e72962bdc6e"
-"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
+"checksum bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a606a02debe2813760609f57a64a2ffd27d9fdf5b2f133eaca0b248dd92cdd2"
"checksum blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182"
"checksum block 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
"checksum bzip2 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42b7c3cbf0fa9c1b82308d57191728ca0256cb821220f4e2fd410a72ade26e3b"
"checksum bzip2-sys 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6584aa36f5ad4c9247f5323b0a42f37802b37a836f0ad87084d7a33961abe25f"
"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101"
+"checksum calloop 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7aa2097be53a00de9e8fc349fea6d76221f398f5c4fa550d420669906962d160"
"checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be"
"checksum cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42aac45e9567d97474a834efdee3081b3c942b2205be932092f53354ce503d6c"
-"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
-"checksum cgl 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "55e7ec0b74fe5897894cbc207092c577e87c52f8a59e8ca8d97ef37551f60a49"
+"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
+"checksum cgl 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff"
"checksum clang-sys 0.22.0 (registry+https://github.com/rust-lang/crates.io-index)" = "939a1a34310b120d26eba35c29475933128b0ec58e24b43327f8dbe6036fc538"
"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
"checksum clipboard-win 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e3a093d6fed558e5fe24c3dfc85a68bb68f1c824f440d3ba5aca189e2998786b"
@@ -2582,22 +2528,22 @@ dependencies = [
"checksum core-foundation-sys 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e7ca8a5221364ef15ce201e8ed2f609fc312682a8f4e0e3d4aa5879764e0fa3b"
"checksum core-graphics 0.17.3 (registry+https://github.com/rust-lang/crates.io-index)" = "56790968ab1c8a1202a102e6de05fc6e1ec87da99e4e93e9a7d13efbfc1e95a9"
"checksum core-text 13.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "12684243b314c95600a2b49628fb775f91d97bbe18424522f665b77014f2a640"
+"checksum core-video-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8dc065219542086f72d1e9f7aadbbab0989e980263695d129d502082d063a9d0"
"checksum crc32fast 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ba125de2af0df55319f41944744ad91c71113bf74a4646efff39afe1f6842db1"
-"checksum crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa"
"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71"
"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9"
"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b"
"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
"checksum deflate 0.7.20 (registry+https://github.com/rust-lang/crates.io-index)" = "707b6a7b384888a70c8d2e8650b3e60170dfc6a67bb4aa67b6dfca57af4bedb4"
-"checksum derivative 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "942ca430eef7a3806595a6737bc388bf51adb888d3fc0dd1b50f1c170167ee3a"
"checksum dirs 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "3fd78930633bd1c6e35c4b42b1df7b0cbc6bc191146e512bb3bedf243fcc3901"
+"checksum dispatch 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e93ca78226c51902d7aa8c12c988338aadd9e85ed9c6be8aaac39192ff3605"
"checksum dlib 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "77e51249a9d823a4cb79e3eca6dcd756153e8ed0157b6c04775d04bf1b13b76a"
"checksum downcast-rs 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "f2b92dfd5c2f75260cbf750572f95d387e7ca0ba5e3fbe9e1a33f23025be020f"
"checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e"
"checksum dunce 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0ad6bf6a88548d1126045c413548df1453d9be094a8ab9fd59bf1fdd338da4f"
"checksum dwrote 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0bd1369e02db5e9b842a9b67bce8a2fcc043beafb2ae8a799dd482d46ea1ff0d"
-"checksum either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "5527cfe0d098f36e3f8839852688e63c8fff1c90b2b405aef730615f9a7bcf7b"
-"checksum embed-resource 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e1419cfb011b3f11cbe865738cc2a36cc574437de4e3f2a1a57f118b230aa4f3"
+"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
+"checksum embed-resource 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bbaba4684ab0af1cbb3ef0b1f540ddc4b57b31940c920ea594efe09ab86e2a6c"
"checksum env_logger 0.5.13 (registry+https://github.com/rust-lang/crates.io-index)" = "15b0a4d2e39f8420210be8b27eeda28029729e2fd4291019455016c348240c38"
"checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
"checksum euclid 0.20.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89c879a4e57d6a2785d517b0771ea6857916173debef0102bf81142d36ca9254"
@@ -2605,7 +2551,7 @@ dependencies = [
"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
"checksum filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd7380b54ced79dda72ecc35cc4fbbd1da6bba54afaa37e96fd1c2a308cd469"
-"checksum flate2 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "2adaffba6388640136149e18ed080b77a78611c1e1d6de75aedcdf78df5d4682"
+"checksum flate2 1.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ad3c5233c9a940c8719031b423d7e6c16af66e031cb0420b0896f5245bf181d3"
"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
"checksum foreign-types 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
"checksum foreign-types 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3684708dacd3b83f4bbe6506d4ccb08bed3c16f521d34366f131b9ecd1884431"
@@ -2620,19 +2566,17 @@ dependencies = [
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571"
-"checksum gif 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "86c2f2b597d6e05c86ee5947b2223bda468fe8dad3e88e2a6520869322aaf568"
-"checksum gl_generator 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "39a23d5e872a275135d66895d954269cf5e8661d234eb1c2480f4ce0d586acbd"
+"checksum gif 0.10.3 (registry+https://github.com/rust-lang/crates.io-index)" = "471d90201b3b223f3451cd4ad53e34295f16a1df17b1edf3736d47761c3981af"
"checksum gl_generator 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ca98bbde17256e02d17336a6bdb5a50f7d0ccacee502e191d3e3d0ec2f96f84a"
-"checksum gleam 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)" = "cae10d7c99d0e77b4766e850a60898a17c1abaf01075531f1066f03dc7dc5fc5"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
-"checksum glutin 0.21.1 (registry+https://github.com/rust-lang/crates.io-index)" = "938ce7a2b1bbfe1535166133bea3f9c1b46350d2794b49561303575e9e1b9949"
-"checksum glutin_egl_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "23f48987ab6cb2b61ad903b59e54a2fd0c380a7baff68cffd6826b69a73dd326"
-"checksum glutin_emscripten_sys 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "245b3fdb08df6ffed7585365851f8404af9c7e2dd4b59f15262e968b6a95a0c7"
-"checksum glutin_gles2_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "89996c30857ae1b4de4b5189abf1ea822a20a9fe9e1c93e5e7b862ff0bdd5cdf"
-"checksum glutin_glx_sys 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1290a5ca5e46fcfa7f66f949cc9d9194b2cb6f2ed61892c8c2b82343631dba57"
-"checksum glutin_wgl_sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f801bbc91efc22dd1c4818a47814fc72bf74d024510451b119381579bfa39021"
+"checksum glutin 0.22.0-alpha3 (git+https://github.com/chrisduerr/glutin)" = "<none>"
+"checksum glutin_egl_sys 0.1.3 (git+https://github.com/chrisduerr/glutin)" = "<none>"
+"checksum glutin_emscripten_sys 0.1.0 (git+https://github.com/chrisduerr/glutin)" = "<none>"
+"checksum glutin_gles2_sys 0.1.3 (git+https://github.com/chrisduerr/glutin)" = "<none>"
+"checksum glutin_glx_sys 0.1.5 (git+https://github.com/chrisduerr/glutin)" = "<none>"
+"checksum glutin_wgl_sys 0.1.3 (git+https://github.com/chrisduerr/glutin)" = "<none>"
"checksum http_req 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7a3235907ba93aeeb84419957956ab7055f1cc4aacfabd4cd1f32f49addab3ec"
-"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114"
+"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
"checksum image 0.21.3 (registry+https://github.com/rust-lang/crates.io-index)" = "35371e467cd7b0b3d1d6013d619203658467df12d61b0ca43cd67b743b1965eb"
"checksum inflate 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1cdb29978cc5797bd8dcc8e5bf7de604891df2a8dc576973d71a281e916db2ff"
@@ -2685,9 +2629,9 @@ dependencies = [
"checksum objc 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "31d20fd2b37e07cf5125be68357b588672e8cefe9a96f8c17a9d46053b3e590d"
"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 openssl 0.10.24 (registry+https://github.com/rust-lang/crates.io-index)" = "8152bb5a9b5b721538462336e3bef9a539f892715e5037fda0f984577311af15"
+"checksum openssl 0.10.25 (registry+https://github.com/rust-lang/crates.io-index)" = "2f372b2b53ce10fb823a337aaa674e3a7d072b957c6264d0f4ff0bd86e657449"
"checksum openssl-probe 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "77af24da69f9d9341038eba93a073b1fdaaa1b788221b00a69bce9e762cb32de"
-"checksum openssl-sys 0.9.49 (registry+https://github.com/rust-lang/crates.io-index)" = "f4fad9e54bd23bd4cbbe48fdc08a1b8091707ac869ef8508edea2fec77dcc884"
+"checksum openssl-sys 0.9.50 (registry+https://github.com/rust-lang/crates.io-index)" = "2c42dcccb832556b5926bc9ae61e8775f2a61e725ab07ab3d1e7fcf8ae62c3b6"
"checksum ordered-float 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "18869315e81473c951eb56ad5558bbc56978562d3ecfb87abb7a1e944cea4518"
"checksum osmesa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "88cfece6e95d2e717e0872a7f53a8684712ad13822a7979bc760b9c77ec0013b"
"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252"
@@ -2703,13 +2647,13 @@ dependencies = [
"checksum podio 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "780fb4b6698bbf9cf2444ea5d22411cef2953f0824b98f33cf454ec5615645bd"
"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b"
"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
-"checksum proc-macro2 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8"
+"checksum proc-macro2 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afdc77cc74ec70ed262262942ebb7dac3d479e9e5cfa2da1841c0806f6cdabcc"
"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
-"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c"
+"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412"
"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
@@ -2722,6 +2666,7 @@ dependencies = [
"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
+"checksum raw-window-handle 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3a292ac09586acd898a72f802519c2997b1eb2caec9bc4c5a06d7259d986a296"
"checksum rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83a27732a533a1be0a0035a111fe76db89ad312f6f0347004c220c57f209a123"
"checksum rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b"
"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
@@ -2738,19 +2683,19 @@ dependencies = [
"checksum rustc_tools_util 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b725dadae9fabc488df69a287f5a99c5eaf5d10853842a8a3dfac52476f544ee"
"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
"checksum rusttype 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "310942406a39981bed7e12b09182a221a29e0990f3e7e0c971f131922ed135d5"
-"checksum rusttype 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "07c67d4df90dcc0296c39e293fa9cfbbd29def131a5a3ffb9bc671f8dc906942"
+"checksum rusttype 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6fa38506b5cbf2fb67f915e2725cb5012f1b9a785b0ab55c4733acda5f6554ef"
"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
"checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421"
-"checksum schannel 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "f2f6abf258d99c3c1c5c2131d99d064e94b7b3dd5f416483057f308fea253339"
+"checksum schannel 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "87f550b06b6cba9c8b8be3ee73f391990116bf527450d2556e9b9ce263b9a021"
"checksum scoped_threadpool 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8"
"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
"checksum security-framework 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "eee63d0f4a9ec776eeb30e220f0bc1e092c3ad744b2a379e3993070364d3adc2"
"checksum security-framework-sys 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "9636f8989cbf61385ae4824b98c1aaa54c994d7d8b41f11c601ed799f0549a56"
"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
-"checksum serde 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)" = "f4473e8506b213730ff2061073b48fa51dcc66349219e2e7c5608f0296a1d95a"
-"checksum serde_derive 1.0.100 (registry+https://github.com/rust-lang/crates.io-index)" = "11e410fde43e157d789fc290d26bc940778ad0fdd47836426fbac36573710dbb"
-"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704"
+"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd"
+"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e"
+"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2"
"checksum serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "38b08a9a90e5260fe01c6480ec7c811606df6d3a660415808c3c3fa8ed95b582"
"checksum servo-fontconfig 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a088f8d775a5c5314aae09bd77340bc9c67d72b9a45258be34c83548b4814cd9"
"checksum servo-fontconfig-sys 4.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b46d201addcfbd25c1798ad1281d98c40743824e0b0f1e611bd3d5d0d31a7b8d"
@@ -2760,7 +2705,6 @@ dependencies = [
"checksum siphasher 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac"
"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"
-"checksum smithay-client-toolkit 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2ccb8c57049b2a34d2cc2b203fa785020ba0129d31920ef0d317430adaf748fa"
"checksum smithay-client-toolkit 0.6.4 (registry+https://github.com/rust-lang/crates.io-index)" = "93960e8975909fcb14cc755de93af2149d8b8f4eb368315537d40cfd0f324054"
"checksum smithay-clipboard 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "315c3f4417d365483dcbaed9ba6488d9f176e43d83f3e1d581050f1c93869e3d"
"checksum socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85"
@@ -2797,15 +2741,10 @@ dependencies = [
"checksum vte 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4f42f536e22f7fcbb407639765c8fd78707a33109301f834a594758bedd6e8cf"
"checksum walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e"
"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d"
-"checksum wayland-client 0.21.13 (registry+https://github.com/rust-lang/crates.io-index)" = "49963e5f9eeaf637bfcd1b9f0701c99fd5cd05225eb51035550d4272806f2713"
"checksum wayland-client 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "af1080ebe0efabcf12aef2132152f616038f2d7dcbbccf7b2d8c5270fe14bcda"
-"checksum wayland-commons 0.21.13 (registry+https://github.com/rust-lang/crates.io-index)" = "40c08896768b667e1df195d88a62a53a2d1351a1ed96188be79c196b35bb32ec"
"checksum wayland-commons 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "bb66b0d1a27c39bbce712b6372131c6e25149f03ffb0cd017cf8f7de8d66dbdb"
-"checksum wayland-protocols 0.21.13 (registry+https://github.com/rust-lang/crates.io-index)" = "4afde2ea2a428eee6d7d2c8584fdbe8b82eee8b6c353e129a434cd6e07f42145"
"checksum wayland-protocols 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc286643656742777d55dc8e70d144fa4699e426ca8e9d4ef454f4bf15ffcf9"
-"checksum wayland-scanner 0.21.13 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3828c568714507315ee425a9529edc4a4aa9901409e373e9e0027e7622b79e"
"checksum wayland-scanner 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93b02247366f395b9258054f964fe293ddd019c3237afba9be2ccbe9e1651c3d"
-"checksum wayland-sys 0.21.13 (registry+https://github.com/rust-lang/crates.io-index)" = "520ab0fd578017a0ee2206623ba9ef4afe5e8f23ca7b42f6acfba2f4e66b1628"
"checksum wayland-sys 0.23.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d94e89a86e6d6d7c7c9b19ebf48a03afaac4af6bc22ae570e9a24124b75358f4"
"checksum which 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e84a603e7e0b1ce1aa1ee2b109c7be00155ce52df5081590d1ffb93f4f515cb2"
"checksum widestring 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "effc0e4ff8085673ea7b9b2e3c73f6bd4d118810c9009ed8f1e16bd96c331db6"
@@ -2816,9 +2755,9 @@ dependencies = [
"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
"checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9"
-"checksum winit 0.19.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7d0da905e61ae52d55c5ca6f8bea1e09daf5e325b6c77b0947c65a5179b49f5f"
+"checksum winit 0.20.0-alpha3 (git+https://github.com/rust-windowing/winit)" = "<none>"
"checksum winpty-sys 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dade7ecea144b3578a02925f93900f32370abfb8768630883971f4ef716b568"
-"checksum winreg 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a27a759395c1195c4cc5cda607ef6f8f6498f64e78f7900f5de0a127a424704a"
+"checksum winreg 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9"
"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
"checksum x11-clipboard 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "89bd49c06c9eb5d98e6ba6536cf64ac9f7ee3a009b2f53996d405b3944f6bcea"
"checksum x11-dl 2.18.4 (registry+https://github.com/rust-lang/crates.io-index)" = "be65e1342a3baae65439cd03306778831a3d133b0d20243a7fb83fd5cf403c58"
diff --git a/alacritty/Cargo.toml b/alacritty/Cargo.toml
index c93f7c56..c47aae6c 100644
--- a/alacritty/Cargo.toml
+++ b/alacritty/Cargo.toml
@@ -14,9 +14,15 @@ clap = "2"
log = "0.4"
time = "0.1.40"
env_logger = "0.6.0"
-crossbeam-channel = "0.3.8"
+serde = { version = "1", features = ["derive"] }
serde_yaml = "0.8"
serde_json = "1"
+glutin = { git = "https://github.com/chrisduerr/glutin" }
+notify = "4"
+libc = "0.2"
+unicode-width = "0.1"
+parking_lot = "0.9"
+font = { path = "../font" }
[build-dependencies]
rustc_tools_util = "0.2.0"
@@ -24,9 +30,15 @@ rustc_tools_util = "0.2.0"
[target.'cfg(not(windows))'.dependencies]
xdg = "2"
+[target.'cfg(not(target_os = "macos"))'.dependencies]
+image = "0.21.0"
+
[target.'cfg(any(target_os = "macos", windows))'.dependencies]
dirs = "1.0.2"
+[target.'cfg(not(any(target_os="windows", target_os="macos")))'.dependencies]
+x11-dl = "2"
+
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.7", features = ["impl-default", "winuser", "synchapi", "roerrorapi", "winerror", "wincon", "wincontypes"]}
diff --git a/alacritty/src/cli.rs b/alacritty/src/cli.rs
index d48ab4d7..d5eb12d7 100644
--- a/alacritty/src/cli.rs
+++ b/alacritty/src/cli.rs
@@ -19,9 +19,10 @@ use std::path::{Path, PathBuf};
use clap::{crate_authors, crate_description, crate_name, crate_version, App, Arg};
use log::{self, LevelFilter};
-use alacritty_terminal::config::{Config, Delta, Dimensions, Shell};
+use alacritty_terminal::config::{Delta, Dimensions, Shell, DEFAULT_NAME};
use alacritty_terminal::index::{Column, Line};
-use alacritty_terminal::window::DEFAULT_NAME;
+
+use crate::config::Config;
/// Options specified on the command line
pub struct Options {
@@ -283,9 +284,10 @@ impl Options {
#[cfg(test)]
mod test {
- use alacritty_terminal::config::{Config, DEFAULT_ALACRITTY_CONFIG};
+ use alacritty_terminal::config::DEFAULT_ALACRITTY_CONFIG;
use crate::cli::Options;
+ use crate::config::Config;
#[test]
fn dynamic_title_ignoring_options_by_default() {
diff --git a/alacritty_terminal/src/config/bindings.rs b/alacritty/src/config/bindings.rs
index 00090bbf..17a6d0b7 100644
--- a/alacritty_terminal/src/config/bindings.rs
+++ b/alacritty/src/config/bindings.rs
@@ -15,13 +15,207 @@
use std::fmt;
use std::str::FromStr;
-use glutin::{ModifiersState, MouseButton};
+use glutin::event::{ModifiersState, MouseButton};
+use log::error;
use serde::de::Error as SerdeError;
use serde::de::{self, MapAccess, Unexpected, Visitor};
use serde::{Deserialize, Deserializer};
-use crate::input::{Action, Binding, KeyBinding, MouseBinding};
-use crate::term::TermMode;
+use alacritty_terminal::config::LOG_TARGET_CONFIG;
+use alacritty_terminal::term::TermMode;
+
+/// Describes a state and action to take in that state
+///
+/// This is the shared component of `MouseBinding` and `KeyBinding`
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Binding<T> {
+ /// Modifier keys required to activate binding
+ pub mods: ModifiersState,
+
+ /// String to send to pty if mods and mode match
+ pub action: Action,
+
+ /// Terminal mode required to activate binding
+ pub mode: TermMode,
+
+ /// excluded terminal modes where the binding won't be activated
+ pub notmode: TermMode,
+
+ /// This property is used as part of the trigger detection code.
+ ///
+ /// For example, this might be a key like "G", or a mouse button.
+ pub trigger: T,
+}
+
+/// Bindings that are triggered by a keyboard key
+pub type KeyBinding = Binding<Key>;
+
+/// Bindings that are triggered by a mouse button
+pub type MouseBinding = Binding<MouseButton>;
+
+impl Default for KeyBinding {
+ fn default() -> KeyBinding {
+ KeyBinding {
+ mods: Default::default(),
+ action: Action::Esc(String::new()),
+ mode: TermMode::NONE,
+ notmode: TermMode::NONE,
+ trigger: Key::A,
+ }
+ }
+}
+
+impl Default for MouseBinding {
+ fn default() -> MouseBinding {
+ MouseBinding {
+ mods: Default::default(),
+ action: Action::Esc(String::new()),
+ mode: TermMode::NONE,
+ notmode: TermMode::NONE,
+ trigger: MouseButton::Left,
+ }
+ }
+}
+
+impl<T: Eq> Binding<T> {
+ #[inline]
+ pub fn is_triggered_by(
+ &self,
+ mode: TermMode,
+ mods: ModifiersState,
+ input: &T,
+ relaxed: bool,
+ ) -> bool {
+ // Check input first since bindings are stored in one big list. This is
+ // the most likely item to fail so prioritizing it here allows more
+ // checks to be short circuited.
+ self.trigger == *input
+ && mode.contains(self.mode)
+ && !mode.intersects(self.notmode)
+ && (self.mods == mods || (relaxed && self.mods.relaxed_eq(mods)))
+ }
+
+ #[inline]
+ pub fn triggers_match(&self, binding: &Binding<T>) -> bool {
+ // Check the binding's key and modifiers
+ if self.trigger != binding.trigger || self.mods != binding.mods {
+ return false;
+ }
+
+ // Completely empty modes match all modes
+ if (self.mode.is_empty() && self.notmode.is_empty())
+ || (binding.mode.is_empty() && binding.notmode.is_empty())
+ {
+ return true;
+ }
+
+ // Check for intersection (equality is required since empty does not intersect itself)
+ (self.mode == binding.mode || self.mode.intersects(binding.mode))
+ && (self.notmode == binding.notmode || self.notmode.intersects(binding.notmode))
+ }
+}
+
+#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
+pub enum Action {
+ /// Write an escape sequence.
+ #[serde(skip)]
+ Esc(String),
+
+ /// Paste contents of system clipboard.
+ Paste,
+
+ /// Store current selection into clipboard.
+ Copy,
+
+ /// Paste contents of selection buffer.
+ PasteSelection,
+
+ /// Increase font size.
+ IncreaseFontSize,
+
+ /// Decrease font size.
+ DecreaseFontSize,
+
+ /// Reset font size to the config value.
+ ResetFontSize,
+
+ /// Scroll exactly one page up.
+ ScrollPageUp,
+
+ /// Scroll exactly one page down.
+ ScrollPageDown,
+
+ /// Scroll one line up.
+ ScrollLineUp,
+
+ /// Scroll one line down.
+ ScrollLineDown,
+
+ /// Scroll all the way to the top.
+ ScrollToTop,
+
+ /// Scroll all the way to the bottom.
+ ScrollToBottom,
+
+ /// Clear the display buffer(s) to remove history.
+ ClearHistory,
+
+ /// Run given command.
+ #[serde(skip)]
+ Command(String, Vec<String>),
+
+ /// Hide the Alacritty window.
+ Hide,
+
+ /// Quit Alacritty.
+ Quit,
+
+ /// Clear warning and error notices.
+ ClearLogNotice,
+
+ /// Spawn a new instance of Alacritty.
+ SpawnNewInstance,
+
+ /// Toggle fullscreen.
+ ToggleFullscreen,
+
+ /// Toggle simple fullscreen on macos.
+ #[cfg(target_os = "macos")]
+ ToggleSimpleFullscreen,
+
+ /// Allow receiving char input.
+ ReceiveChar,
+
+ /// No action.
+ None,
+}
+
+impl Default for Action {
+ fn default() -> Action {
+ Action::None
+ }
+}
+
+impl From<&'static str> for Action {
+ fn from(s: &'static str) -> Action {
+ Action::Esc(s.into())
+ }
+}
+
+pub trait RelaxedEq<T: ?Sized = Self> {
+ fn relaxed_eq(&self, other: T) -> bool;
+}
+
+impl RelaxedEq for ModifiersState {
+ // Make sure that modifiers in the config are always present,
+ // but ignore surplus modifiers.
+ fn relaxed_eq(&self, other: Self) -> bool {
+ (!self.logo || other.logo)
+ && (!self.alt || other.alt)
+ && (!self.ctrl || other.ctrl)
+ && (!self.shift || other.shift)
+ }
+}
macro_rules! bindings {
(
@@ -444,8 +638,8 @@ pub enum Key {
}
impl Key {
- pub fn from_glutin_input(key: ::glutin::VirtualKeyCode) -> Self {
- use glutin::VirtualKeyCode::*;
+ pub fn from_glutin_input(key: glutin::event::VirtualKeyCode) -> Self {
+ use glutin::event::VirtualKeyCode::*;
// Thank you, vim macros and regex!
match key {
Key1 => Key::Key1,
@@ -646,7 +840,7 @@ impl<'a> Deserialize<'a> for ModeWrapper {
"~appkeypad" => res.not_mode |= TermMode::APP_KEYPAD,
"~alt" => res.not_mode |= TermMode::ALT_SCREEN,
"alt" => res.mode |= TermMode::ALT_SCREEN,
- _ => error!("Unknown mode {:?}", modifier),
+ _ => error!(target: LOG_TARGET_CONFIG, "Unknown mode {:?}", modifier),
}
}
@@ -812,7 +1006,7 @@ impl<'a> Deserialize<'a> for RawBinding {
let mut mods: Option<ModifiersState> = None;
let mut key: Option<Key> = None;
let mut chars: Option<String> = None;
- let mut action: Option<crate::input::Action> = None;
+ let mut action: Option<Action> = None;
let mut mode: Option<TermMode> = None;
let mut not_mode: Option<TermMode> = None;
let mut mouse: Option<MouseButton> = None;
@@ -1010,7 +1204,7 @@ impl<'a> de::Deserialize<'a> for ModsWrapper {
"alt" | "option" => res.alt = true,
"control" => res.ctrl = true,
"none" => (),
- _ => error!("Unknown modifier {:?}", modifier),
+ _ => error!(target: LOG_TARGET_CONFIG, "Unknown modifier {:?}", modifier),
}
}
@@ -1021,3 +1215,195 @@ impl<'a> de::Deserialize<'a> for ModsWrapper {
deserializer.deserialize_str(ModsVisitor)
}
}
+
+#[cfg(test)]
+mod test {
+ use glutin::event::ModifiersState;
+
+ use alacritty_terminal::term::TermMode;
+
+ use crate::config::{Action, Binding};
+
+ type MockBinding = Binding<usize>;
+
+ impl Default for MockBinding {
+ fn default() -> Self {
+ Self {
+ mods: Default::default(),
+ action: Default::default(),
+ mode: TermMode::empty(),
+ notmode: TermMode::empty(),
+ trigger: Default::default(),
+ }
+ }
+ }
+
+ #[test]
+ fn binding_matches_itself() {
+ let binding = MockBinding::default();
+ let identical_binding = MockBinding::default();
+
+ assert!(binding.triggers_match(&identical_binding));
+ assert!(identical_binding.triggers_match(&binding));
+ }
+
+ #[test]
+ fn binding_matches_different_action() {
+ let binding = MockBinding::default();
+ let mut different_action = MockBinding::default();
+ different_action.action = Action::ClearHistory;
+
+ assert!(binding.triggers_match(&different_action));
+ assert!(different_action.triggers_match(&binding));
+ }
+
+ #[test]
+ fn mods_binding_requires_strict_match() {
+ let mut superset_mods = MockBinding::default();
+ superset_mods.mods = ModifiersState { alt: true, logo: true, ctrl: true, shift: true };
+ let mut subset_mods = MockBinding::default();
+ subset_mods.mods = ModifiersState { alt: true, logo: false, ctrl: false, shift: false };
+
+ assert!(!superset_mods.triggers_match(&subset_mods));
+ assert!(!subset_mods.triggers_match(&superset_mods));
+ }
+
+ #[test]
+ fn binding_matches_identical_mode() {
+ let mut b1 = MockBinding::default();
+ b1.mode = TermMode::ALT_SCREEN;
+ let mut b2 = MockBinding::default();
+ b2.mode = TermMode::ALT_SCREEN;
+
+ assert!(b1.triggers_match(&b2));
+ }
+
+ #[test]
+ fn binding_without_mode_matches_any_mode() {
+ let b1 = MockBinding::default();
+ let mut b2 = MockBinding::default();
+ b2.mode = TermMode::APP_KEYPAD;
+ b2.notmode = TermMode::ALT_SCREEN;
+
+ assert!(b1.triggers_match(&b2));
+ }
+
+ #[test]
+ fn binding_with_mode_matches_empty_mode() {
+ let mut b1 = MockBinding::default();
+ b1.mode = TermMode::APP_KEYPAD;
+ b1.notmode = TermMode::ALT_SCREEN;
+ let b2 = MockBinding::default();
+
+ assert!(b1.triggers_match(&b2));
+ }
+
+ #[test]
+ fn binding_matches_superset_mode() {
+ let mut b1 = MockBinding::default();
+ b1.mode = TermMode::APP_KEYPAD;
+ let mut b2 = MockBinding::default();
+ b2.mode = TermMode::ALT_SCREEN | TermMode::APP_KEYPAD;
+
+ assert!(b1.triggers_match(&b2));
+ }
+
+ #[test]
+ fn binding_matches_subset_mode() {
+ let mut b1 = MockBinding::default();
+ b1.mode = TermMode::ALT_SCREEN | TermMode::APP_KEYPAD;
+ let mut b2 = MockBinding::default();
+ b2.mode = TermMode::APP_KEYPAD;
+
+ assert!(b1.triggers_match(&b2));
+ }
+
+ #[test]
+ fn binding_matches_partial_intersection() {
+ let mut b1 = MockBinding::default();
+ b1.mode = TermMode::ALT_SCREEN | TermMode::APP_KEYPAD;
+ let mut b2 = MockBinding::default();
+ b2.mode = TermMode::APP_KEYPAD | TermMode::APP_CURSOR;
+
+ assert!(b1.triggers_match(&b2));
+ }
+
+ #[test]
+ fn binding_mismatches_notmode() {
+ let mut b1 = MockBinding::default();
+ b1.mode = TermMode::ALT_SCREEN;
+ let mut b2 = MockBinding::default();
+ b2.notmode = TermMode::ALT_SCREEN;
+
+ assert!(!b1.triggers_match(&b2));
+ }
+
+ #[test]
+ fn binding_mismatches_unrelated() {
+ let mut b1 = MockBinding::default();
+ b1.mode = TermMode::ALT_SCREEN;
+ let mut b2 = MockBinding::default();
+ b2.mode = TermMode::APP_KEYPAD;
+
+ assert!(!b1.triggers_match(&b2));
+ }
+
+ #[test]
+ fn binding_trigger_input() {
+ let mut binding = MockBinding::default();
+ binding.trigger = 13;
+
+ let mods = binding.mods;
+ let mode = binding.mode;
+
+ assert!(binding.is_triggered_by(mode, mods, &13, true));
+ assert!(!binding.is_triggered_by(mode, mods, &32, true));
+ }
+
+ #[test]
+ fn binding_trigger_mods() {
+ let mut binding = MockBinding::default();
+ binding.mods = ModifiersState { alt: true, logo: true, ctrl: false, shift: false };
+
+ let superset_mods = ModifiersState { alt: true, logo: true, ctrl: true, shift: true };
+ let subset_mods = ModifiersState { alt: false, logo: false, ctrl: false, shift: false };
+
+ let t = binding.trigger;
+ let mode = binding.mode;
+
+ assert!(binding.is_triggered_by(mode, binding.mods, &t, true));
+ assert!(binding.is_triggered_by(mode, binding.mods, &t, false));
+
+ assert!(binding.is_triggered_by(mode, superset_mods, &t, true));
+ assert!(!binding.is_triggered_by(mode, superset_mods, &t, false));
+
+ assert!(!binding.is_triggered_by(mode, subset_mods, &t, true));
+ assert!(!binding.is_triggered_by(mode, subset_mods, &t, false));
+ }
+
+ #[test]
+ fn binding_trigger_modes() {
+ let mut binding = MockBinding::default();
+ binding.mode = TermMode::ALT_SCREEN;
+
+ let t = binding.trigger;
+ let mods = binding.mods;
+
+ assert!(!binding.is_triggered_by(TermMode::INSERT, mods, &t, true));
+ assert!(binding.is_triggered_by(TermMode::ALT_SCREEN, mods, &t, true));
+ assert!(binding.is_triggered_by(TermMode::ALT_SCREEN | TermMode::INSERT, mods, &t, true));
+ }
+
+ #[test]
+ fn binding_trigger_notmodes() {
+ let mut binding = MockBinding::default();
+ binding.notmode = TermMode::ALT_SCREEN;
+
+ let t = binding.trigger;
+ let mods = binding.mods;
+
+ assert!(binding.is_triggered_by(TermMode::INSERT, mods, &t, true));
+ assert!(!binding.is_triggered_by(TermMode::ALT_SCREEN, mods, &t, true));
+ assert!(!binding.is_triggered_by(TermMode::ALT_SCREEN | TermMode::INSERT, mods, &t, true));
+ }
+}
diff --git a/alacritty/src/config.rs b/alacritty/src/config/mod.rs
index 6d185fe7..fe0ee7af 100644
--- a/alacritty/src/config.rs
+++ b/alacritty/src/config/mod.rs
@@ -11,9 +11,23 @@ use serde_yaml;
#[cfg(not(windows))]
use xdg;
-use alacritty_terminal::config::{Config, DEFAULT_ALACRITTY_CONFIG};
+use alacritty_terminal::config::{
+ Config as TermConfig, DEFAULT_ALACRITTY_CONFIG, LOG_TARGET_CONFIG,
+};
-pub const SOURCE_FILE_PATH: &str = file!();
+mod bindings;
+pub mod monitor;
+mod mouse;
+#[cfg(test)]
+mod test;
+mod ui_config;
+
+pub use crate::config::bindings::{Action, Binding, Key, RelaxedEq};
+#[cfg(test)]
+pub use crate::config::mouse::{ClickHandler, Mouse};
+use crate::config::ui_config::UIConfig;
+
+pub type Config = TermConfig<UIConfig>;
/// Result from config loading
pub type Result<T> = ::std::result::Result<T, Error>;
@@ -169,7 +183,7 @@ pub fn reload_from(path: &PathBuf) -> Result<Config> {
match read_config(path) {
Ok(config) => Ok(config),
Err(err) => {
- error!("Unable to load config {:?}: {}", path, err);
+ error!(target: LOG_TARGET_CONFIG, "Unable to load config {:?}: {}", path, err);
Err(err)
},
}
@@ -199,16 +213,21 @@ fn read_config(path: &PathBuf) -> Result<Config> {
fn print_deprecation_warnings(config: &Config) {
if config.window.start_maximized.is_some() {
warn!(
+ target: LOG_TARGET_CONFIG,
"Config window.start_maximized is deprecated; please use window.startup_mode instead"
);
}
if config.render_timer.is_some() {
- warn!("Config render_timer is deprecated; please use debug.render_timer instead");
+ warn!(
+ target: LOG_TARGET_CONFIG,
+ "Config render_timer is deprecated; please use debug.render_timer instead"
+ );
}
if config.persistent_logging.is_some() {
warn!(
+ target: LOG_TARGET_CONFIG,
"Config persistent_logging is deprecated; please use debug.persistent_logging instead"
);
}
diff --git a/alacritty_terminal/src/config/monitor.rs b/alacritty/src/config/monitor.rs
index 6d2ab41a..8dc5379a 100644
--- a/alacritty_terminal/src/config/monitor.rs
+++ b/alacritty/src/config/monitor.rs
@@ -4,43 +4,24 @@ use std::time::Duration;
use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
-pub struct Monitor {
- _thread: ::std::thread::JoinHandle<()>,
- rx: mpsc::Receiver<PathBuf>,
-}
+use alacritty_terminal::event::{Event, EventListener};
+use alacritty_terminal::util;
-pub trait OnConfigReload {
- fn on_config_reload(&mut self);
-}
+use crate::event::EventProxy;
-impl OnConfigReload for crate::display::Notifier {
- fn on_config_reload(&mut self) {
- self.notify();
- }
+pub struct Monitor {
+ _thread: ::std::thread::JoinHandle<()>,
}
impl Monitor {
- /// Get pending config changes
- pub fn pending(&self) -> Option<PathBuf> {
- let mut config = None;
- while let Ok(new) = self.rx.try_recv() {
- config = Some(new);
- }
-
- config
- }
-
- pub fn new<H, P>(path: P, mut handler: H) -> Monitor
+ pub fn new<P>(path: P, event_proxy: EventProxy) -> Monitor
where
- H: OnConfigReload + Send + 'static,
P: Into<PathBuf>,
{
let path = path.into();
- let (config_tx, config_rx) = mpsc::channel();
-
Monitor {
- _thread: crate::util::thread::spawn_named("config watcher", move || {
+ _thread: util::thread::spawn_named("config watcher", move || {
let (tx, rx) = mpsc::channel();
// The Duration argument is a debouncing period.
let mut watcher =
@@ -66,14 +47,12 @@ impl Monitor {
continue;
}
- let _ = config_tx.send(path);
- handler.on_config_reload();
+ event_proxy.send_event(Event::ConfigReload(path));
},
_ => {},
}
}
}),
- rx: config_rx,
}
}
}
diff --git a/alacritty_terminal/src/config/mouse.rs b/alacritty/src/config/mouse.rs
index 7a04cbe7..b7832b4a 100644
--- a/alacritty_terminal/src/config/mouse.rs
+++ b/alacritty/src/config/mouse.rs
@@ -1,10 +1,12 @@
use std::time::Duration;
-use glutin::ModifiersState;
+use glutin::event::ModifiersState;
+use log::error;
use serde::{Deserialize, Deserializer};
+use alacritty_terminal::config::{failure_default, LOG_TARGET_CONFIG};
+
use crate::config::bindings::{CommandWrapper, ModsWrapper};
-use crate::config::failure_default;
#[serde(default)]
#[derive(Default, Clone, Debug, Deserialize, PartialEq, Eq)]
@@ -56,7 +58,12 @@ where
match <Option<CommandWrapper>>::deserialize(val) {
Ok(launcher) => Ok(launcher),
Err(err) => {
- error!("Problem with config: {}; using {}", err, default.clone().unwrap().program());
+ error!(
+ target: LOG_TARGET_CONFIG,
+ "Problem with config: {}; using {}",
+ err,
+ default.clone().unwrap().program()
+ );
Ok(default)
},
}
@@ -101,7 +108,7 @@ where
match u64::deserialize(value) {
Ok(threshold_ms) => Ok(Duration::from_millis(threshold_ms)),
Err(err) => {
- error!("Problem with config: {}; using default value", err);
+ error!(target: LOG_TARGET_CONFIG, "Problem with config: {}; using default value", err);
Ok(default_threshold_ms())
},
}
diff --git a/alacritty_terminal/src/config/test.rs b/alacritty/src/config/test.rs
index e7890922..8da6cef5 100644
--- a/alacritty_terminal/src/config/test.rs
+++ b/alacritty/src/config/test.rs
@@ -1,4 +1,6 @@
-use crate::config::{Config, DEFAULT_ALACRITTY_CONFIG};
+use alacritty_terminal::config::DEFAULT_ALACRITTY_CONFIG;
+
+use crate::config::Config;
#[test]
fn parse_config() {
@@ -6,10 +8,10 @@ fn parse_config() {
::serde_yaml::from_str(DEFAULT_ALACRITTY_CONFIG).expect("deserialize config");
// Sanity check that mouse bindings are being parsed
- assert!(!config.mouse_bindings.is_empty());
+ assert!(!config.ui_config.mouse_bindings.is_empty());
// Sanity check that key bindings are being parsed
- assert!(!config.key_bindings.is_empty());
+ assert!(!config.ui_config.key_bindings.is_empty());
}
#[test]
diff --git a/alacritty/src/config/ui_config.rs b/alacritty/src/config/ui_config.rs
new file mode 100644
index 00000000..6230c5bb
--- /dev/null
+++ b/alacritty/src/config/ui_config.rs
@@ -0,0 +1,63 @@
+use serde::{Deserialize, Deserializer};
+
+use alacritty_terminal::config::failure_default;
+
+use crate::config::bindings::{self, Binding, KeyBinding, MouseBinding};
+use crate::config::mouse::Mouse;
+
+#[derive(Debug, PartialEq, Deserialize)]
+pub struct UIConfig {
+ #[serde(default, deserialize_with = "failure_default")]
+ pub mouse: Mouse,
+
+ /// Keybindings
+ #[serde(default = "default_key_bindings", deserialize_with = "deserialize_key_bindings")]
+ pub key_bindings: Vec<KeyBinding>,
+
+ /// Bindings for the mouse
+ #[serde(default = "default_mouse_bindings", deserialize_with = "deserialize_mouse_bindings")]
+ pub mouse_bindings: Vec<MouseBinding>,
+}
+
+fn default_key_bindings() -> Vec<KeyBinding> {
+ bindings::default_key_bindings()
+}
+
+fn default_mouse_bindings() -> Vec<MouseBinding> {
+ bindings::default_mouse_bindings()
+}
+
+fn deserialize_key_bindings<'a, D>(deserializer: D) -> Result<Vec<KeyBinding>, D::Error>
+where
+ D: Deserializer<'a>,
+{
+ deserialize_bindings(deserializer, bindings::default_key_bindings())
+}
+
+fn deserialize_mouse_bindings<'a, D>(deserializer: D) -> Result<Vec<MouseBinding>, D::Error>
+where
+ D: Deserializer<'a>,
+{
+ deserialize_bindings(deserializer, bindings::default_mouse_bindings())
+}
+
+fn deserialize_bindings<'a, D, T>(
+ deserializer: D,
+ mut default: Vec<Binding<T>>,
+) -> Result<Vec<Binding<T>>, D::Error>
+where
+ D: Deserializer<'a>,
+ T: Copy + Eq,
+ Binding<T>: Deserialize<'a>,
+{
+ let mut bindings: Vec<Binding<T>> = failure_default(deserializer)?;
+
+ // Remove matching default bindings
+ for binding in bindings.iter() {
+ default.retain(|b| !b.triggers_match(binding));
+ }
+
+ bindings.extend(default);
+
+ Ok(bindings)
+}
diff --git a/alacritty/src/display.rs b/alacritty/src/display.rs
new file mode 100644
index 00000000..a8f72b3e
--- /dev/null
+++ b/alacritty/src/display.rs
@@ -0,0 +1,476 @@
+// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! The display subsystem including window management, font rasterization, and
+//! GPU drawing.
+use std::cmp::max;
+use std::f64;
+use std::fmt;
+use std::time::Instant;
+
+use glutin::dpi::{PhysicalPosition, PhysicalSize};
+use glutin::event_loop::EventLoop;
+use log::{debug, info};
+use parking_lot::MutexGuard;
+
+use font::{self, Rasterize, Size};
+
+use alacritty_terminal::config::StartupMode;
+use alacritty_terminal::event::{Event, OnResize};
+use alacritty_terminal::index::Line;
+use alacritty_terminal::message_bar::MessageBuffer;
+use alacritty_terminal::meter::Meter;
+use alacritty_terminal::renderer::rects::{RenderLines, RenderRect};
+use alacritty_terminal::renderer::{self, GlyphCache, QuadRenderer};
+use alacritty_terminal::term::color::Rgb;
+use alacritty_terminal::term::{RenderableCell, SizeInfo, Term};
+
+use crate::config::Config;
+use crate::event::{FontResize, Resize};
+use crate::window::{self, Window};
+
+/// Font size change interval
+pub const FONT_SIZE_STEP: f32 = 0.5;
+
+#[derive(Debug)]
+pub enum Error {
+ /// Error with window management
+ Window(window::Error),
+
+ /// Error dealing with fonts
+ Font(font::Error),
+
+ /// Error in renderer
+ Render(renderer::Error),
+
+ /// Error during buffer swap
+ ContextError(glutin::ContextError),
+}
+
+impl std::error::Error for Error {
+ fn cause(&self) -> Option<&dyn (std::error::Error)> {
+ match *self {
+ Error::Window(ref err) => Some(err),
+ Error::Font(ref err) => Some(err),
+ Error::Render(ref err) => Some(err),
+ Error::ContextError(ref err) => Some(err),
+ }
+ }
+
+ fn description(&self) -> &str {
+ match *self {
+ Error::Window(ref err) => err.description(),
+ Error::Font(ref err) => err.description(),
+ Error::Render(ref err) => err.description(),
+ Error::ContextError(ref err) => err.description(),
+ }
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match *self {
+ Error::Window(ref err) => err.fmt(f),
+ Error::Font(ref err) => err.fmt(f),
+ Error::Render(ref err) => err.fmt(f),
+ Error::ContextError(ref err) => err.fmt(f),
+ }
+ }
+}
+
+impl From<window::Error> for Error {
+ fn from(val: window::Error) -> Error {
+ Error::Window(val)
+ }
+}
+
+impl From<font::Error> for Error {
+ fn from(val: font::Error) -> Error {
+ Error::Font(val)
+ }
+}
+
+impl From<renderer::Error> for Error {
+ fn from(val: renderer::Error) -> Error {
+ Error::Render(val)
+ }
+}
+
+impl From<glutin::ContextError> for Error {
+ fn from(val: glutin::ContextError) -> Error {
+ Error::ContextError(val)
+ }
+}
+
+/// The display wraps a window, font rasterizer, and GPU renderer
+pub struct Display {
+ pub size_info: SizeInfo,
+ pub font_size: Size,
+ pub window: Window,
+
+ renderer: QuadRenderer,
+ glyph_cache: GlyphCache,
+ meter: Meter,
+}
+
+impl Display {
+ pub fn new(config: &Config, event_loop: &EventLoop<Event>) -> Result<Display, Error> {
+ // Guess DPR based on first monitor
+ let estimated_dpr =
+ event_loop.available_monitors().next().map(|m| m.hidpi_factor()).unwrap_or(1.);
+
+ // Guess the target window dimensions
+ let metrics = GlyphCache::static_metrics(config.font.clone(), estimated_dpr)?;
+ let (cell_width, cell_height) = compute_cell_size(config, &metrics);
+ let dimensions =
+ GlyphCache::calculate_dimensions(config, estimated_dpr, cell_width, cell_height);
+
+ debug!("Estimated DPR: {}", estimated_dpr);
+ debug!("Estimated Cell Size: {} x {}", cell_width, cell_height);
+ debug!("Estimated Dimensions: {:?}", dimensions);
+
+ // Create the window where Alacritty will be displayed
+ let logical = dimensions.map(|d| PhysicalSize::new(d.0, d.1).to_logical(estimated_dpr));
+
+ // Spawn window
+ let mut window = Window::new(event_loop, &config, logical)?;
+
+ let dpr = window.hidpi_factor();
+ info!("Device pixel ratio: {}", dpr);
+
+ // get window properties for initializing the other subsystems
+ let mut viewport_size = window.inner_size().to_physical(dpr);
+
+ // Create renderer
+ let mut renderer = QuadRenderer::new()?;
+
+ let (glyph_cache, cell_width, cell_height) =
+ Self::new_glyph_cache(dpr, &mut renderer, config)?;
+
+ let mut padding_x = f32::from(config.window.padding.x) * dpr as f32;
+ let mut padding_y = f32::from(config.window.padding.y) * dpr as f32;
+
+ if let Some((width, height)) =
+ GlyphCache::calculate_dimensions(config, dpr, cell_width, cell_height)
+ {
+ let PhysicalSize { width: w, height: h } = window.inner_size().to_physical(dpr);
+ if (w - width).abs() < f64::EPSILON && (h - height).abs() < f64::EPSILON {
+ info!("Estimated DPR correctly, skipping resize");
+ } else {
+ viewport_size = PhysicalSize::new(width, height);
+ window.set_inner_size(viewport_size.to_logical(dpr));
+ }
+ } else if config.window.dynamic_padding {
+ // Make sure additional padding is spread evenly
+ 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_x = padding_x.floor();
+ padding_y = padding_y.floor();
+
+ info!("Cell Size: {} x {}", cell_width, cell_height);
+ info!("Padding: {} x {}", padding_x, padding_y);
+
+ let size_info = SizeInfo {
+ dpr,
+ width: viewport_size.width as f32,
+ height: viewport_size.height as f32,
+ cell_width: cell_width as f32,
+ cell_height: cell_height as f32,
+ padding_x: padding_x as f32,
+ padding_y: padding_y as f32,
+ };
+
+ // Update OpenGL projection
+ renderer.resize(&size_info);
+
+ // Clear screen
+ let background_color = config.colors.primary.background;
+ renderer.with_api(&config, &size_info, |api| {
+ api.clear(background_color);
+ });
+
+ // We should call `clear` when window is offscreen, so when `window.show()` happens it
+ // would be with background color instead of uninitialized surface.
+ window.swap_buffers();
+
+ window.set_visible(true);
+
+ // Set window position
+ //
+ // TODO: replace `set_position` with `with_position` once available
+ // Upstream issue: https://github.com/tomaka/winit/issues/806
+ if let Some(position) = config.window.position {
+ let physical = PhysicalPosition::from((position.x, position.y));
+ let logical = physical.to_logical(dpr);
+ window.set_outer_position(logical);
+ }
+
+ #[allow(clippy::single_match)]
+ match config.window.startup_mode() {
+ StartupMode::Fullscreen => window.set_fullscreen(true),
+ #[cfg(target_os = "macos")]
+ StartupMode::SimpleFullscreen => window.set_simple_fullscreen(true),
+ #[cfg(not(any(target_os = "macos", windows)))]
+ StartupMode::Maximized => window.set_maximized(true),
+ _ => (),
+ }
+
+ Ok(Display {
+ window,
+ renderer,
+ glyph_cache,
+ meter: Meter::new(),
+ size_info,
+ font_size: config.font.size,
+ })
+ }
+
+ fn new_glyph_cache(
+ dpr: f64,
+ renderer: &mut QuadRenderer,
+ config: &Config,
+ ) -> Result<(GlyphCache, f32, f32), Error> {
+ let font = config.font.clone();
+ let rasterizer = font::Rasterizer::new(dpr as f32, config.font.use_thin_strokes())?;
+
+ // Initialize glyph cache
+ let glyph_cache = {
+ info!("Initializing glyph cache...");
+ let init_start = Instant::now();
+
+ let cache =
+ renderer.with_loader(|mut api| GlyphCache::new(rasterizer, &font, &mut api))?;
+
+ let stop = init_start.elapsed();
+ let stop_f = stop.as_secs() as f64 + f64::from(stop.subsec_nanos()) / 1_000_000_000f64;
+ info!("... finished initializing glyph cache in {}s", stop_f);
+
+ cache
+ };
+
+ // Need font metrics to resize the window properly. This suggests to me the
+ // font metrics should be computed before creating the window in the first
+ // place so that a resize is not needed.
+ let (cw, ch) = compute_cell_size(config, &glyph_cache.font_metrics());
+
+ Ok((glyph_cache, cw, ch))
+ }
+
+ /// Update font size and cell dimensions
+ fn update_glyph_cache(&mut self, config: &Config, size: Size) {
+ let size_info = &mut self.size_info;
+ let cache = &mut self.glyph_cache;
+
+ let font = config.font.clone().with_size(size);
+
+ self.renderer.with_loader(|mut api| {
+ let _ = cache.update_font_size(font, size_info.dpr, &mut api);
+ });
+
+ // Update cell size
+ let (cell_width, cell_height) = compute_cell_size(config, &self.glyph_cache.font_metrics());
+ size_info.cell_width = cell_width;
+ size_info.cell_height = cell_height;
+ }
+
+ /// Process resize events
+ pub fn handle_resize<T>(
+ &mut self,
+ terminal: &mut Term<T>,
+ pty_resize_handle: &mut dyn OnResize,
+ message_buffer: &MessageBuffer,
+ config: &Config,
+ resize_pending: Resize,
+ ) {
+ // Update font size and cell dimensions
+ if let Some(resize) = resize_pending.font_size {
+ self.font_size = match resize {
+ FontResize::Delta(delta) => max(self.font_size + delta, FONT_SIZE_STEP.into()),
+ FontResize::Reset => config.font.size,
+ };
+
+ self.update_glyph_cache(config, self.font_size);
+ }
+
+ // Update the window dimensions
+ if let Some(size) = resize_pending.dimensions {
+ self.size_info.width = size.width as f32;
+ self.size_info.height = size.height as f32;
+ }
+
+ let dpr = self.size_info.dpr;
+ let width = self.size_info.width;
+ let height = self.size_info.height;
+ let cell_width = self.size_info.cell_width;
+ let cell_height = self.size_info.cell_height;
+
+ // Recalculate padding
+ let mut padding_x = f32::from(config.window.padding.x) * dpr as f32;
+ let mut padding_y = f32::from(config.window.padding.y) * dpr as f32;
+
+ if config.window.dynamic_padding {
+ padding_x = dynamic_padding(padding_x, width, cell_width);
+ padding_y = dynamic_padding(padding_y, height, cell_height);
+ }
+
+ self.size_info.padding_x = padding_x.floor() as f32;
+ self.size_info.padding_y = padding_y.floor() as f32;
+
+ let mut pty_size = self.size_info;
+
+ // Subtract message bar lines from pty size
+ if resize_pending.message_buffer.is_some() {
+ let lines =
+ message_buffer.message().map(|m| m.text(&self.size_info).len()).unwrap_or(0);
+ pty_size.height -= pty_size.cell_height * lines as f32;
+ }
+
+ // Resize PTY
+ pty_resize_handle.on_resize(&pty_size);
+
+ // Resize terminal
+ terminal.resize(&pty_size);
+
+ // Resize renderer
+ let physical =
+ PhysicalSize::new(f64::from(self.size_info.width), f64::from(self.size_info.height));
+ self.renderer.resize(&self.size_info);
+ self.window.resize(physical);
+ }
+
+ /// Draw the screen
+ ///
+ /// A reference to Term whose state is being drawn must be provided.
+ ///
+ /// This call may block if vsync is enabled
+ pub fn draw<T>(
+ &mut self,
+ terminal: MutexGuard<'_, Term<T>>,
+ message_buffer: &MessageBuffer,
+ config: &Config,
+ ) {
+ let grid_cells: Vec<RenderableCell> = terminal.renderable_cells(config).collect();
+ let visual_bell_intensity = terminal.visual_bell.intensity();
+ let background_color = terminal.background_color();
+ let metrics = self.glyph_cache.font_metrics();
+ let glyph_cache = &mut self.glyph_cache;
+ let size_info = self.size_info;
+
+ // Update IME position
+ #[cfg(not(windows))]
+ self.window.update_ime_position(&terminal, &self.size_info);
+
+ // Drop terminal as early as possible to free lock
+ drop(terminal);
+
+ self.renderer.with_api(&config, &size_info, |api| {
+ api.clear(background_color);
+ });
+
+ let mut lines = RenderLines::new();
+
+ // Draw grid
+ {
+ let _sampler = self.meter.sampler();
+
+ self.renderer.with_api(&config, &size_info, |mut api| {
+ // Iterate over all non-empty cells in the grid
+ for cell in grid_cells {
+ // Update underline/strikeout
+ lines.update(cell);
+
+ // Draw the cell
+ api.render_cell(cell, glyph_cache);
+ }
+ });
+ }
+
+ let mut rects = lines.into_rects(&metrics, &size_info);
+
+ if let Some(message) = message_buffer.message() {
+ let text = message.text(&size_info);
+
+ // Create a new rectangle for the background
+ let start_line = size_info.lines().0 - text.len();
+ let y = size_info.padding_y + size_info.cell_height * start_line as f32;
+ rects.push(RenderRect::new(
+ 0.,
+ y,
+ size_info.width,
+ size_info.height - y,
+ message.color(),
+ ));
+
+ // Draw rectangles including the new background
+ self.renderer.draw_rects(
+ &size_info,
+ config.visual_bell.color,
+ visual_bell_intensity,
+ rects,
+ );
+
+ // Relay messages to the user
+ let mut offset = 1;
+ for message_text in text.iter().rev() {
+ self.renderer.with_api(&config, &size_info, |mut api| {
+ api.render_string(
+ &message_text,
+ Line(size_info.lines().saturating_sub(offset)),
+ glyph_cache,
+ None,
+ );
+ });
+ offset += 1;
+ }
+ } else {
+ // Draw rectangles
+ self.renderer.draw_rects(
+ &size_info,
+ config.visual_bell.color,
+ visual_bell_intensity,
+ rects,
+ );
+ }
+
+ // Draw render timer
+ if config.render_timer() {
+ let timing = format!("{:.3} usec", self.meter.average());
+ let color = Rgb { r: 0xd5, g: 0x4e, b: 0x53 };
+ self.renderer.with_api(&config, &size_info, |mut api| {
+ api.render_string(&timing[..], size_info.lines() - 2, glyph_cache, Some(color));
+ });
+ }
+
+ self.window.swap_buffers();
+ }
+}
+
+/// Calculate padding to spread it evenly around the terminal content
+#[inline]
+fn dynamic_padding(padding: f32, dimension: f32, cell_dimension: f32) -> f32 {
+ padding + ((dimension - 2. * padding) % cell_dimension) / 2.
+}
+
+/// Calculate the cell dimensions based on font metrics.
+#[inline]
+fn compute_cell_size(config: &Config, metrics: &font::Metrics) -> (f32, f32) {
+ let offset_x = f64::from(config.font.offset.x);
+ let offset_y = f64::from(config.font.offset.y);
+ (
+ f32::max(1., ((metrics.average_advance + offset_x) as f32).floor()),
+ f32::max(1., ((metrics.line_height + offset_y) as f32).floor()),
+ )
+}
diff --git a/alacritty/src/event.rs b/alacritty/src/event.rs
new file mode 100644
index 00000000..984352d4
--- /dev/null
+++ b/alacritty/src/event.rs
@@ -0,0 +1,651 @@
+//! Process window events
+use std::borrow::Cow;
+use std::env;
+#[cfg(unix)]
+use std::fs;
+use std::fs::File;
+use std::io::Write;
+use std::sync::Arc;
+use std::time::Instant;
+
+use glutin::dpi::PhysicalSize;
+use glutin::event::{ElementState, Event as GlutinEvent, MouseButton};
+use glutin::event_loop::{ControlFlow, EventLoop, EventLoopProxy};
+use glutin::platform::desktop::EventLoopExtDesktop;
+#[cfg(not(any(target_os = "macos", windows)))]
+use glutin::platform::unix::EventLoopWindowTargetExtUnix;
+use log::{debug, info, warn};
+use serde_json as json;
+
+use font::Size;
+
+use alacritty_terminal::clipboard::ClipboardType;
+use alacritty_terminal::config::LOG_TARGET_CONFIG;
+use alacritty_terminal::event::OnResize;
+use alacritty_terminal::event::{Event, EventListener, Notify};
+use alacritty_terminal::grid::Scroll;
+use alacritty_terminal::index::{Column, Line, Point, Side};
+use alacritty_terminal::message_bar::{Message, MessageBuffer};
+use alacritty_terminal::selection::Selection;
+use alacritty_terminal::sync::FairMutex;
+use alacritty_terminal::term::cell::Cell;
+use alacritty_terminal::term::{SizeInfo, Term};
+use alacritty_terminal::tty;
+use alacritty_terminal::util::{limit, start_daemon};
+
+use crate::config;
+use crate::config::Config;
+use crate::display::Display;
+use crate::input::{self, ActionContext as _, Modifiers};
+use crate::window::Window;
+
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum FontResize {
+ Delta(f32),
+ Reset,
+}
+
+#[derive(Default, Copy, Clone, Debug, PartialEq)]
+pub struct Resize {
+ pub dimensions: Option<PhysicalSize>,
+ pub message_buffer: Option<()>,
+ pub font_size: Option<FontResize>,
+}
+
+impl Resize {
+ fn is_empty(&self) -> bool {
+ self.dimensions.is_none() && self.font_size.is_none() && self.message_buffer.is_none()
+ }
+}
+
+pub struct ActionContext<'a, N, T> {
+ pub notifier: &'a mut N,
+ pub terminal: &'a mut Term<T>,
+ pub size_info: &'a mut SizeInfo,
+ pub mouse: &'a mut Mouse,
+ pub received_count: &'a mut usize,
+ pub suppress_chars: &'a mut bool,
+ pub modifiers: &'a mut Modifiers,
+ pub window: &'a mut Window,
+ pub message_buffer: &'a mut MessageBuffer,
+ pub resize_pending: &'a mut Resize,
+ pub font_size: &'a Size,
+}
+
+impl<'a, N: Notify + 'a, T: EventListener> input::ActionContext<T> for ActionContext<'a, N, T> {
+ fn write_to_pty<B: Into<Cow<'static, [u8]>>>(&mut self, val: B) {
+ self.notifier.notify(val);
+ }
+
+ fn size_info(&self) -> SizeInfo {
+ *self.size_info
+ }
+
+ fn scroll(&mut self, scroll: Scroll) {
+ self.terminal.scroll_display(scroll);
+
+ if let ElementState::Pressed = self.mouse().left_button_state {
+ let (x, y) = (self.mouse().x, self.mouse().y);
+ let size_info = self.size_info();
+ let point = size_info.pixels_to_coords(x, y);
+ let cell_side = self.mouse().cell_side;
+ self.update_selection(Point { line: point.line, col: point.col }, cell_side);
+ }
+ }
+
+ fn copy_selection(&mut self, ty: ClipboardType) {
+ if let Some(selected) = self.terminal.selection_to_string() {
+ if !selected.is_empty() {
+ self.terminal.clipboard().store(ty, selected);
+ }
+ }
+ }
+
+ fn selection_is_empty(&self) -> bool {
+ self.terminal.selection().as_ref().map(Selection::is_empty).unwrap_or(true)
+ }
+
+ fn clear_selection(&mut self) {
+ *self.terminal.selection_mut() = None;
+ self.terminal.dirty = true;
+ }
+
+ fn update_selection(&mut self, point: Point, side: Side) {
+ let point = self.terminal.visible_to_buffer(point);
+
+ // Update selection if one exists
+ if let Some(ref mut selection) = self.terminal.selection_mut() {
+ selection.update(point, side);
+ }
+
+ self.terminal.dirty = true;
+ }
+
+ fn simple_selection(&mut self, point: Point, side: Side) {
+ let point = self.terminal.visible_to_buffer(point);
+ *self.terminal.selection_mut() = Some(Selection::simple(point, side));
+ self.terminal.dirty = true;
+ }
+
+ fn block_selection(&mut self, point: Point, side: Side) {
+ let point = self.terminal.visible_to_buffer(point);
+ *self.terminal.selection_mut() = Some(Selection::block(point, side));
+ self.terminal.dirty = true;
+ }
+
+ fn semantic_selection(&mut self, point: Point) {
+ let point = self.terminal.visible_to_buffer(point);
+ *self.terminal.selection_mut() = Some(Selection::semantic(point));
+ self.terminal.dirty = true;
+ }
+
+ fn line_selection(&mut self, point: Point) {
+ let point = self.terminal.visible_to_buffer(point);
+ *self.terminal.selection_mut() = Some(Selection::lines(point));
+ self.terminal.dirty = true;
+ }
+
+ fn mouse_coords(&self) -> Option<Point> {
+ let x = self.mouse.x as usize;
+ let y = self.mouse.y as usize;
+
+ if self.size_info.contains_point(x, y, true) {
+ Some(self.size_info.pixels_to_coords(x, y))
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ fn mouse_mut(&mut self) -> &mut Mouse {
+ self.mouse
+ }
+
+ #[inline]
+ fn mouse(&self) -> &Mouse {
+ self.mouse
+ }
+
+ #[inline]
+ fn received_count(&mut self) -> &mut usize {
+ &mut self.received_count
+ }
+
+ #[inline]
+ fn suppress_chars(&mut self) -> &mut bool {
+ &mut self.suppress_chars
+ }
+
+ #[inline]
+ fn modifiers(&mut self) -> &mut Modifiers {
+ &mut self.modifiers
+ }
+
+ #[inline]
+ fn window(&self) -> &Window {
+ self.window
+ }
+
+ #[inline]
+ fn window_mut(&mut self) -> &mut Window {
+ self.window
+ }
+
+ #[inline]
+ fn terminal(&self) -> &Term<T> {
+ self.terminal
+ }
+
+ #[inline]
+ fn terminal_mut(&mut self) -> &mut Term<T> {
+ self.terminal
+ }
+
+ fn spawn_new_instance(&mut self) {
+ let alacritty = env::args().next().unwrap();
+
+ #[cfg(unix)]
+ let args = {
+ #[cfg(not(target_os = "freebsd"))]
+ let proc_prefix = "";
+ #[cfg(target_os = "freebsd")]
+ let proc_prefix = "/compat/linux";
+ let link_path = format!("{}/proc/{}/cwd", proc_prefix, tty::child_pid());
+ if let Ok(path) = fs::read_link(link_path) {
+ vec!["--working-directory".into(), path]
+ } else {
+ Vec::new()
+ }
+ };
+ #[cfg(not(unix))]
+ let args: Vec<String> = Vec::new();
+
+ match start_daemon(&alacritty, &args) {
+ Ok(_) => debug!("Started new Alacritty process: {} {:?}", alacritty, args),
+ Err(_) => warn!("Unable to start new Alacritty process: {} {:?}", alacritty, args),
+ }
+ }
+
+ fn change_font_size(&mut self, delta: f32) {
+ self.resize_pending.font_size = Some(FontResize::Delta(delta));
+ self.terminal.dirty = true;
+ }
+
+ fn reset_font_size(&mut self) {
+ self.resize_pending.font_size = Some(FontResize::Reset);
+ self.terminal.dirty = true;
+ }
+
+ fn pop_message(&mut self) {
+ self.resize_pending.message_buffer = Some(());
+ self.message_buffer.pop();
+ }
+
+ fn message(&self) -> Option<&Message> {
+ self.message_buffer.message()
+ }
+}
+
+pub enum ClickState {
+ None,
+ Click,
+ DoubleClick,
+ TripleClick,
+}
+
+/// State of the mouse
+pub struct Mouse {
+ pub x: usize,
+ pub y: usize,
+ pub left_button_state: ElementState,
+ pub middle_button_state: ElementState,
+ pub right_button_state: ElementState,
+ pub last_click_timestamp: Instant,
+ pub click_state: ClickState,
+ pub scroll_px: i32,
+ pub line: Line,
+ pub column: Column,
+ pub cell_side: Side,
+ pub lines_scrolled: f32,
+ pub block_url_launcher: bool,
+ pub last_button: MouseButton,
+}
+
+impl Default for Mouse {
+ fn default() -> Mouse {
+ Mouse {
+ x: 0,
+ y: 0,
+ last_click_timestamp: Instant::now(),
+ left_button_state: ElementState::Released,
+ middle_button_state: ElementState::Released,
+ right_button_state: ElementState::Released,
+ click_state: ClickState::None,
+ scroll_px: 0,
+ line: Line(0),
+ column: Column(0),
+ cell_side: Side::Left,
+ lines_scrolled: 0.0,
+ block_url_launcher: false,
+ last_button: MouseButton::Other(0),
+ }
+ }
+}
+
+/// The event processor
+///
+/// Stores some state from received events and dispatches actions when they are
+/// triggered.
+pub struct Processor<N> {
+ notifier: N,
+ mouse: Mouse,
+ received_count: usize,
+ suppress_chars: bool,
+ modifiers: Modifiers,
+ config: Config,
+ pty_resize_handle: Box<dyn OnResize>,
+ message_buffer: MessageBuffer,
+ display: Display,
+}
+
+impl<N: Notify> Processor<N> {
+ /// Create a new event processor
+ ///
+ /// Takes a writer which is expected to be hooked up to the write end of a
+ /// pty.
+ pub fn new(
+ notifier: N,
+ pty_resize_handle: Box<dyn OnResize>,
+ message_buffer: MessageBuffer,
+ config: Config,
+ display: Display,
+ ) -> Processor<N> {
+ Processor {
+ notifier,
+ mouse: Default::default(),
+ received_count: 0,
+ suppress_chars: false,
+ modifiers: Default::default(),
+ config,
+ pty_resize_handle,
+ message_buffer,
+ display,
+ }
+ }
+
+ /// Run the event loop.
+ pub fn run<T>(&mut self, terminal: Arc<FairMutex<Term<T>>>, mut event_loop: EventLoop<Event>)
+ where
+ T: EventListener,
+ {
+ #[cfg(not(any(target_os = "macos", windows)))]
+ let mut dpr_initialized = false;
+
+ let mut event_queue = Vec::new();
+
+ event_loop.run_return(|event, _event_loop, control_flow| {
+ if self.config.debug.print_events {
+ info!("glutin event: {:?}", event);
+ }
+
+ match (&event, tty::process_should_exit()) {
+ // Check for shutdown
+ (GlutinEvent::UserEvent(Event::Exit), _) | (_, true) => {
+ *control_flow = ControlFlow::Exit;
+ return;
+ },
+ // Process events
+ (GlutinEvent::EventsCleared, _) => {
+ *control_flow = ControlFlow::Wait;
+
+ if event_queue.is_empty() {
+ return;
+ }
+ },
+ // Buffer events
+ _ => {
+ *control_flow = ControlFlow::Poll;
+ if !Self::skip_event(&event) {
+ event_queue.push(event);
+ }
+ return;
+ },
+ }
+
+ let mut terminal = terminal.lock();
+
+ let mut resize_pending = Resize::default();
+
+ let context = ActionContext {
+ terminal: &mut terminal,
+ notifier: &mut self.notifier,
+ mouse: &mut self.mouse,
+ size_info: &mut self.display.size_info,
+ received_count: &mut self.received_count,
+ suppress_chars: &mut self.suppress_chars,
+ modifiers: &mut self.modifiers,
+ message_buffer: &mut self.message_buffer,
+ resize_pending: &mut resize_pending,
+ window: &mut self.display.window,
+ font_size: &self.display.font_size,
+ };
+ let mut processor = input::Processor::new(context, &mut self.config);
+
+ for event in event_queue.drain(..) {
+ Processor::handle_event(event, &mut processor);
+ }
+
+ // TODO: Workaround for incorrect startup DPI on X11
+ // https://github.com/rust-windowing/winit/issues/998
+ #[cfg(not(any(target_os = "macos", windows)))]
+ {
+ if !dpr_initialized && _event_loop.is_x11() {
+ dpr_initialized = true;
+
+ let dpr = self.display.window.hidpi_factor();
+ self.display.size_info.dpr = dpr;
+
+ let size = self.display.window.inner_size().to_physical(dpr);
+
+ resize_pending.font_size = Some(FontResize::Delta(0.));
+ resize_pending.dimensions = Some(size);
+
+ terminal.dirty = true;
+ }
+ }
+
+ // Process resize events
+ if !resize_pending.is_empty() {
+ self.display.handle_resize(
+ &mut terminal,
+ self.pty_resize_handle.as_mut(),
+ &self.message_buffer,
+ &self.config,
+ resize_pending,
+ );
+ }
+
+ if terminal.dirty {
+ // Clear dirty flag
+ terminal.dirty = !terminal.visual_bell.completed();
+
+ // Redraw screen
+ self.display.draw(terminal, &self.message_buffer, &self.config);
+ }
+ });
+
+ // Write ref tests to disk
+ self.write_ref_test_results(&terminal.lock());
+ }
+
+ /// Handle events from glutin
+ ///
+ /// Doesn't take self mutably due to borrow checking. Kinda uggo but w/e.
+ fn handle_event<T>(
+ event: GlutinEvent<Event>,
+ processor: &mut input::Processor<T, ActionContext<N, T>>,
+ ) where
+ T: EventListener,
+ {
+ match event {
+ GlutinEvent::UserEvent(event) => match event {
+ Event::Title(title) => processor.ctx.window.set_title(&title),
+ Event::Wakeup => processor.ctx.terminal.dirty = true,
+ Event::Urgent => {
+ processor.ctx.window.set_urgent(!processor.ctx.terminal.is_focused)
+ },
+ Event::ConfigReload(path) => {
+ processor.ctx.message_buffer.remove_target(LOG_TARGET_CONFIG);
+ processor.ctx.resize_pending.message_buffer = Some(());
+
+ if let Ok(config) = config::reload_from(&path) {
+ processor.ctx.terminal.update_config(&config);
+
+ if *processor.ctx.font_size == processor.config.font.size {
+ processor.ctx.resize_pending.font_size = Some(FontResize::Reset);
+ }
+
+ *processor.config = config;
+
+ processor.ctx.terminal.dirty = true;
+ }
+ },
+ Event::Message(message) => {
+ processor.ctx.message_buffer.push(message);
+ processor.ctx.resize_pending.message_buffer = Some(());
+ processor.ctx.terminal.dirty = true;
+ },
+ Event::MouseCursorDirty => processor.reset_mouse_cursor(),
+ Event::Exit => (),
+ },
+ GlutinEvent::WindowEvent { event, window_id, .. } => {
+ use glutin::event::WindowEvent::*;
+ match event {
+ CloseRequested => processor.ctx.terminal.exit(),
+ Resized(lsize) => {
+ let psize = lsize.to_physical(processor.ctx.size_info.dpr);
+ processor.ctx.resize_pending.dimensions = Some(psize);
+ processor.ctx.terminal.dirty = true;
+ },
+ KeyboardInput { input, .. } => {
+ processor.process_key(input);
+ if input.state == ElementState::Pressed {
+ // Hide cursor while typing
+ if processor.config.ui_config.mouse.hide_when_typing {
+ processor.ctx.window.set_mouse_visible(false);
+ }
+ }
+ },
+ ReceivedCharacter(c) => processor.received_char(c),
+ MouseInput { state, button, modifiers, .. } => {
+ if !cfg!(target_os = "macos") || processor.ctx.terminal.is_focused {
+ processor.ctx.window.set_mouse_visible(true);
+ processor.mouse_input(state, button, modifiers);
+ processor.ctx.terminal.dirty = true;
+ }
+ },
+ CursorMoved { position: lpos, modifiers, .. } => {
+ let (x, y) = lpos.to_physical(processor.ctx.size_info.dpr).into();
+ let x: i32 = limit(x, 0, processor.ctx.size_info.width as i32);
+ let y: i32 = limit(y, 0, processor.ctx.size_info.height as i32);
+
+ processor.ctx.window.set_mouse_visible(true);
+ processor.mouse_moved(x as usize, y as usize, modifiers);
+ },
+ MouseWheel { delta, phase, modifiers, .. } => {
+ processor.ctx.window.set_mouse_visible(true);
+ processor.on_mouse_wheel(delta, phase, modifiers);
+ },
+ Focused(is_focused) => {
+ if window_id == processor.ctx.window.window_id() {
+ processor.ctx.terminal.is_focused = is_focused;
+ processor.ctx.terminal.dirty = true;
+
+ if is_focused {
+ processor.ctx.window.set_urgent(false);
+ } else {
+ processor.ctx.window.set_mouse_visible(true);
+ }
+
+ processor.on_focus_change(is_focused);
+ }
+ },
+ DroppedFile(path) => {
+ let path: String = path.to_string_lossy().into();
+ processor.ctx.write_to_pty(path.into_bytes());
+ },
+ HiDpiFactorChanged(dpr) => {
+ let dpr_change = (dpr / processor.ctx.size_info.dpr) as f32;
+ let resize_pending = &mut processor.ctx.resize_pending;
+
+ // Push current font to update its DPR
+ resize_pending.font_size = Some(FontResize::Delta(0.));
+
+ // Scale window dimensions with new DPR
+ let old_width = processor.ctx.size_info.width;
+ let old_height = processor.ctx.size_info.height;
+ let dimensions = resize_pending.dimensions.get_or_insert_with(|| {
+ PhysicalSize::new(f64::from(old_width), f64::from(old_height))
+ });
+ dimensions.width *= f64::from(dpr_change);
+ dimensions.height *= f64::from(dpr_change);
+
+ processor.ctx.terminal.dirty = true;
+ processor.ctx.size_info.dpr = dpr;
+ },
+ RedrawRequested => processor.ctx.terminal.dirty = true,
+ TouchpadPressure { .. }
+ | CursorEntered { .. }
+ | CursorLeft { .. }
+ | AxisMotion { .. }
+ | HoveredFileCancelled
+ | Destroyed
+ | HoveredFile(_)
+ | Touch(_)
+ | Moved(_) => (),
+ // TODO: Add support for proper modifier handling
+ ModifiersChanged { .. } => (),
+ }
+ },
+ GlutinEvent::DeviceEvent { .. }
+ | GlutinEvent::Suspended { .. }
+ | GlutinEvent::NewEvents { .. }
+ | GlutinEvent::EventsCleared
+ | GlutinEvent::Resumed
+ | GlutinEvent::LoopDestroyed => (),
+ }
+ }
+
+ /// Check if an event is irrelevant and can be skipped
+ fn skip_event(event: &GlutinEvent<Event>) -> bool {
+ match event {
+ GlutinEvent::UserEvent(Event::Exit) => true,
+ GlutinEvent::WindowEvent { event, .. } => {
+ use glutin::event::WindowEvent::*;
+ match event {
+ TouchpadPressure { .. }
+ | CursorEntered { .. }
+ | CursorLeft { .. }
+ | AxisMotion { .. }
+ | HoveredFileCancelled
+ | Destroyed
+ | HoveredFile(_)
+ | Touch(_)
+ | Moved(_) => true,
+ _ => false,
+ }
+ },
+ GlutinEvent::DeviceEvent { .. }
+ | GlutinEvent::Suspended { .. }
+ | GlutinEvent::NewEvents { .. }
+ | GlutinEvent::EventsCleared
+ | GlutinEvent::LoopDestroyed => true,
+ _ => false,
+ }
+ }
+
+ // Write the ref test results to the disk
+ pub fn write_ref_test_results<T>(&self, terminal: &Term<T>) {
+ if !self.config.debug.ref_test {
+ return;
+ }
+
+ // dump grid state
+ let mut grid = terminal.grid().clone();
+ grid.initialize_all(&Cell::default());
+ grid.truncate();
+
+ let serialized_grid = json::to_string(&grid).expect("serialize grid");
+
+ let serialized_size = json::to_string(&self.display.size_info).expect("serialize size");
+
+ let serialized_config = format!("{{\"history_size\":{}}}", grid.history_size());
+
+ File::create("./grid.json")
+ .and_then(|mut f| f.write_all(serialized_grid.as_bytes()))
+ .expect("write grid.json");
+
+ File::create("./size.json")
+ .and_then(|mut f| f.write_all(serialized_size.as_bytes()))
+ .expect("write size.json");
+
+ File::create("./config.json")
+ .and_then(|mut f| f.write_all(serialized_config.as_bytes()))
+ .expect("write config.json");
+ }
+}
+
+#[derive(Debug, Clone)]
+pub struct EventProxy(EventLoopProxy<Event>);
+
+impl EventProxy {
+ pub fn new(proxy: EventLoopProxy<Event>) -> Self {
+ EventProxy(proxy)
+ }
+}
+
+impl EventListener for EventProxy {
+ fn send_event(&self, event: Event) {
+ let _ = self.0.send_event(event);
+ }
+}
diff --git a/alacritty_terminal/src/input.rs b/alacritty/src/input.rs
index e268bf62..be6a030e 100644
--- a/alacritty_terminal/src/input.rs
+++ b/alacritty/src/input.rs
@@ -18,44 +18,45 @@
//! In order to figure that out, state about which modifier keys are pressed
//! needs to be tracked. Additionally, we need a bit of a state machine to
//! determine what to do when a non-modifier key is pressed.
-use crate::url::Url;
use std::borrow::Cow;
+use std::marker::PhantomData;
use std::mem;
use std::time::Instant;
-use glutin::{
- ElementState, KeyboardInput, ModifiersState, MouseButton, MouseCursor, MouseScrollDelta,
- TouchPhase, VirtualKeyCode,
+use glutin::event::{
+ ElementState, KeyboardInput, ModifiersState, MouseButton, MouseScrollDelta, TouchPhase,
+ VirtualKeyCode,
};
-
-use crate::ansi::{ClearMode, Handler};
-use crate::clipboard::ClipboardType;
-use crate::config::{self, Key};
+use glutin::window::CursorIcon;
+use log::{debug, trace, warn};
+
+use alacritty_terminal::ansi::{ClearMode, Handler};
+use alacritty_terminal::clipboard::ClipboardType;
+use alacritty_terminal::event::EventListener;
+use alacritty_terminal::grid::Scroll;
+use alacritty_terminal::index::{Column, Line, Point, Side};
+use alacritty_terminal::message_bar::{self, Message};
+use alacritty_terminal::term::mode::TermMode;
+use alacritty_terminal::term::{SizeInfo, Term};
+use alacritty_terminal::url::Url;
+use alacritty_terminal::util::start_daemon;
+
+use crate::config::{Action, Binding, Config, Key, RelaxedEq};
+use crate::display::FONT_SIZE_STEP;
use crate::event::{ClickState, Mouse};
-use crate::grid::Scroll;
-use crate::index::{Column, Line, Point, Side};
-use crate::message_bar::{self, Message};
-use crate::term::mode::TermMode;
-use crate::term::{SizeInfo, Term};
-use crate::util::start_daemon;
-
-pub const FONT_SIZE_STEP: f32 = 0.5;
+use crate::window::Window;
/// Processes input from glutin.
///
/// An escape sequence may be emitted in case specific keys or key combinations
/// are activated.
-pub struct Processor<'a, A: 'a> {
- pub key_bindings: &'a [KeyBinding],
- pub mouse_bindings: &'a [MouseBinding],
- pub mouse_config: &'a config::Mouse,
- pub scrolling_config: &'a config::Scrolling,
+pub struct Processor<'a, T: EventListener, A: ActionContext<T> + 'a> {
pub ctx: A,
- pub save_to_clipboard: bool,
- pub alt_send_esc: bool,
+ pub config: &'a mut Config,
+ _phantom: PhantomData<T>,
}
-pub trait ActionContext {
+pub trait ActionContext<T: EventListener> {
fn write_to_pty<B: Into<Cow<'static, [u8]>>>(&mut self, _: B);
fn size_info(&self) -> SizeInfo;
fn copy_selection(&mut self, _: ClipboardType);
@@ -73,13 +74,15 @@ pub trait ActionContext {
fn suppress_chars(&mut self) -> &mut bool;
fn modifiers(&mut self) -> &mut Modifiers;
fn scroll(&mut self, scroll: Scroll);
- fn hide_window(&mut self);
- fn terminal(&self) -> &Term;
- fn terminal_mut(&mut self) -> &mut Term;
+ fn window(&self) -> &Window;
+ fn window_mut(&mut self) -> &mut Window;
+ fn terminal(&self) -> &Term<T>;
+ fn terminal_mut(&mut self) -> &mut Term<T>;
fn spawn_new_instance(&mut self);
- fn toggle_fullscreen(&mut self);
- #[cfg(target_os = "macos")]
- fn toggle_simple_fullscreen(&mut self);
+ fn change_font_size(&mut self, delta: f32);
+ fn reset_font_size(&mut self);
+ fn pop_message(&mut self);
+ fn message(&self) -> Option<&Message>;
}
#[derive(Debug, Default, Copy, Clone)]
@@ -123,199 +126,21 @@ impl From<&mut Modifiers> for ModifiersState {
}
}
-/// Describes a state and action to take in that state
-///
-/// This is the shared component of `MouseBinding` and `KeyBinding`
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub struct Binding<T> {
- /// Modifier keys required to activate binding
- pub mods: ModifiersState,
-
- /// String to send to pty if mods and mode match
- pub action: Action,
-
- /// Terminal mode required to activate binding
- pub mode: TermMode,
-
- /// excluded terminal modes where the binding won't be activated
- pub notmode: TermMode,
-
- /// This property is used as part of the trigger detection code.
- ///
- /// For example, this might be a key like "G", or a mouse button.
- pub trigger: T,
-}
-
-/// Bindings that are triggered by a keyboard key
-pub type KeyBinding = Binding<Key>;
-
-/// Bindings that are triggered by a mouse button
-pub type MouseBinding = Binding<MouseButton>;
-
-impl Default for KeyBinding {
- fn default() -> KeyBinding {
- KeyBinding {
- mods: Default::default(),
- action: Action::Esc(String::new()),
- mode: TermMode::NONE,
- notmode: TermMode::NONE,
- trigger: Key::A,
- }
- }
-}
-
-impl Default for MouseBinding {
- fn default() -> MouseBinding {
- MouseBinding {
- mods: Default::default(),
- action: Action::Esc(String::new()),
- mode: TermMode::NONE,
- notmode: TermMode::NONE,
- trigger: MouseButton::Left,
- }
- }
-}
-
-impl<T: Eq> Binding<T> {
- #[inline]
- fn is_triggered_by(
- &self,
- mode: TermMode,
- mods: ModifiersState,
- input: &T,
- relaxed: bool,
- ) -> bool {
- // Check input first since bindings are stored in one big list. This is
- // the most likely item to fail so prioritizing it here allows more
- // checks to be short circuited.
- self.trigger == *input
- && mode.contains(self.mode)
- && !mode.intersects(self.notmode)
- && self.mods_match(mods, relaxed)
- }
-
- #[inline]
- pub fn triggers_match(&self, binding: &Binding<T>) -> bool {
- // Check the binding's key and modifiers
- if self.trigger != binding.trigger || self.mods != binding.mods {
- return false;
- }
-
- // Completely empty modes match all modes
- if (self.mode.is_empty() && self.notmode.is_empty())
- || (binding.mode.is_empty() && binding.notmode.is_empty())
- {
- return true;
- }
-
- // Check for intersection (equality is required since empty does not intersect itself)
- (self.mode == binding.mode || self.mode.intersects(binding.mode))
- && (self.notmode == binding.notmode || self.notmode.intersects(binding.notmode))
- }
+trait Execute<T: EventListener> {
+ fn execute<A: ActionContext<T>>(&self, ctx: &mut A, mouse_mode: bool);
}
-impl<T> Binding<T> {
+impl<T, U: EventListener> Execute<U> for Binding<T> {
/// Execute the action associate with this binding
#[inline]
- fn execute<A: ActionContext>(&self, ctx: &mut A, mouse_mode: bool) {
+ fn execute<A: ActionContext<U>>(&self, ctx: &mut A, mouse_mode: bool) {
self.action.execute(ctx, mouse_mode)
}
-
- /// Check that two mods descriptions for equivalence
- #[inline]
- fn mods_match(&self, mods: ModifiersState, relaxed: bool) -> bool {
- if relaxed {
- self.mods.relaxed_eq(mods)
- } else {
- self.mods == mods
- }
- }
}
-#[derive(Debug, Clone, PartialEq, Eq, Deserialize)]
-pub enum Action {
- /// Write an escape sequence.
- #[serde(skip)]
- Esc(String),
-
- /// Paste contents of system clipboard.
- Paste,
-
- /// Store current selection into clipboard.
- Copy,
-
- /// Paste contents of selection buffer.
- PasteSelection,
-
- /// Increase font size.
- IncreaseFontSize,
-
- /// Decrease font size.
- DecreaseFontSize,
-
- /// Reset font size to the config value.
- ResetFontSize,
-
- /// Scroll exactly one page up.
- ScrollPageUp,
-
- /// Scroll exactly one page down.
- ScrollPageDown,
-
- /// Scroll one line up.
- ScrollLineUp,
-
- /// Scroll one line down.
- ScrollLineDown,
-
- /// Scroll all the way to the top.
- ScrollToTop,
-
- /// Scroll all the way to the bottom.
- ScrollToBottom,
-
- /// Clear the display buffer(s) to remove history.
- ClearHistory,
-
- /// Run given command.
- #[serde(skip)]
- Command(String, Vec<String>),
-
- /// Hide the Alacritty window.
- Hide,
-
- /// Quit Alacritty.
- Quit,
-
- /// Clear warning and error notices.
- ClearLogNotice,
-
- /// Spawn a new instance of Alacritty.
- SpawnNewInstance,
-
- /// Toggle fullscreen.
- ToggleFullscreen,
-
- /// Toggle simple fullscreen on macos.
- #[cfg(target_os = "macos")]
- ToggleSimpleFullscreen,
-
- /// Allow receiving char input.
- ReceiveChar,
-
- /// No action.
- None,
-}
-
-impl Default for Action {
- fn default() -> Action {
- Action::None
- }
-}
-
-impl Action {
+impl<T: EventListener> Execute<T> for Action {
#[inline]
- fn execute<A: ActionContext>(&self, ctx: &mut A, mouse_mode: bool) {
+ fn execute<A: ActionContext<T>>(&self, ctx: &mut A, mouse_mode: bool) {
match *self {
Action::Esc(ref s) => {
ctx.scroll(Scroll::Bottom);
@@ -326,13 +151,13 @@ impl Action {
},
Action::Paste => {
let text = ctx.terminal_mut().clipboard().load(ClipboardType::Clipboard);
- self.paste(ctx, &text);
+ paste(ctx, &text);
},
Action::PasteSelection => {
// Only paste if mouse events are not captured by an application
if !mouse_mode {
let text = ctx.terminal_mut().clipboard().load(ClipboardType::Selection);
- self.paste(ctx, &text);
+ paste(ctx, &text);
}
},
Action::Command(ref program, ref args) => {
@@ -343,94 +168,41 @@ impl Action {
Err(err) => warn!("Couldn't run command {}", err),
}
},
- Action::ToggleFullscreen => {
- ctx.toggle_fullscreen();
- },
+ Action::ToggleFullscreen => ctx.window_mut().toggle_fullscreen(),
#[cfg(target_os = "macos")]
- Action::ToggleSimpleFullscreen => {
- ctx.toggle_simple_fullscreen();
- },
- Action::Hide => {
- ctx.hide_window();
- },
- Action::Quit => {
- ctx.terminal_mut().exit();
- },
- Action::IncreaseFontSize => {
- ctx.terminal_mut().change_font_size(FONT_SIZE_STEP);
- },
- Action::DecreaseFontSize => {
- ctx.terminal_mut().change_font_size(-FONT_SIZE_STEP);
- },
- Action::ResetFontSize => {
- ctx.terminal_mut().reset_font_size();
- },
- Action::ScrollPageUp => {
- ctx.scroll(Scroll::PageUp);
- },
- Action::ScrollPageDown => {
- ctx.scroll(Scroll::PageDown);
- },
- Action::ScrollLineUp => {
- ctx.scroll(Scroll::Lines(1));
- },
- Action::ScrollLineDown => {
- ctx.scroll(Scroll::Lines(-1));
- },
- Action::ScrollToTop => {
- ctx.scroll(Scroll::Top);
- },
- Action::ScrollToBottom => {
- ctx.scroll(Scroll::Bottom);
- },
- Action::ClearHistory => {
- ctx.terminal_mut().clear_screen(ClearMode::Saved);
- },
- Action::ClearLogNotice => {
- ctx.terminal_mut().message_buffer_mut().pop();
- },
- Action::SpawnNewInstance => {
- ctx.spawn_new_instance();
- },
+ Action::ToggleSimpleFullscreen => ctx.window_mut().toggle_simple_fullscreen(),
+ Action::Hide => ctx.window().set_visible(false),
+ Action::Quit => ctx.terminal_mut().exit(),
+ Action::IncreaseFontSize => ctx.change_font_size(FONT_SIZE_STEP),
+ Action::DecreaseFontSize => ctx.change_font_size(FONT_SIZE_STEP * -1.),
+ Action::ResetFontSize => ctx.reset_font_size(),
+ Action::ScrollPageUp => ctx.scroll(Scroll::PageUp),
+ Action::ScrollPageDown => ctx.scroll(Scroll::PageDown),
+ Action::ScrollLineUp => ctx.scroll(Scroll::Lines(1)),
+ Action::ScrollLineDown => ctx.scroll(Scroll::Lines(-1)),
+ Action::ScrollToTop => ctx.scroll(Scroll::Top),
+ Action::ScrollToBottom => ctx.scroll(Scroll::Bottom),
+ Action::ClearHistory => ctx.terminal_mut().clear_screen(ClearMode::Saved),
+ Action::ClearLogNotice => ctx.pop_message(),
+ Action::SpawnNewInstance => ctx.spawn_new_instance(),
Action::ReceiveChar | Action::None => (),
}
}
-
- fn paste<A: ActionContext>(&self, ctx: &mut A, contents: &str) {
- if ctx.terminal().mode().contains(TermMode::BRACKETED_PASTE) {
- ctx.write_to_pty(&b"\x1b[200~"[..]);
- ctx.write_to_pty(contents.replace("\x1b", "").into_bytes());
- ctx.write_to_pty(&b"\x1b[201~"[..]);
- } else {
- // In non-bracketed (ie: normal) mode, terminal applications cannot distinguish
- // pasted data from keystrokes.
- // In theory, we should construct the keystrokes needed to produce the data we are
- // pasting... since that's neither practical nor sensible (and probably an impossible
- // task to solve in a general way), we'll just replace line breaks (windows and unix
- // style) with a single carriage return (\r, which is what the Enter key produces).
- ctx.write_to_pty(contents.replace("\r\n", "\r").replace("\n", "\r").into_bytes());
- }
- }
-}
-
-trait RelaxedEq<T: ?Sized = Self> {
- fn relaxed_eq(&self, other: T) -> bool;
}
-impl RelaxedEq for ModifiersState {
- // Make sure that modifiers in the config are always present,
- // but ignore surplus modifiers.
- fn relaxed_eq(&self, other: Self) -> bool {
- (!self.logo || other.logo)
- && (!self.alt || other.alt)
- && (!self.ctrl || other.ctrl)
- && (!self.shift || other.shift)
- }
-}
-
-impl From<&'static str> for Action {
- fn from(s: &'static str) -> Action {
- Action::Esc(s.into())
+fn paste<T: EventListener, A: ActionContext<T>>(ctx: &mut A, contents: &str) {
+ if ctx.terminal().mode().contains(TermMode::BRACKETED_PASTE) {
+ ctx.write_to_pty(&b"\x1b[200~"[..]);
+ ctx.write_to_pty(contents.replace("\x1b", "").into_bytes());
+ ctx.write_to_pty(&b"\x1b[201~"[..]);
+ } else {
+ // In non-bracketed (ie: normal) mode, terminal applications cannot distinguish
+ // pasted data from keystrokes.
+ // In theory, we should construct the keystrokes needed to produce the data we are
+ // pasting... since that's neither practical nor sensible (and probably an impossible
+ // task to solve in a general way), we'll just replace line breaks (windows and unix
+ // style) with a single carriage return (\r, which is what the Enter key produces).
+ ctx.write_to_pty(contents.replace("\r\n", "\r").replace("\n", "\r").into_bytes());
}
}
@@ -443,7 +215,21 @@ pub enum MouseState {
Text,
}
-impl<'a, A: ActionContext + 'a> Processor<'a, A> {
+impl From<MouseState> for CursorIcon {
+ fn from(mouse_state: MouseState) -> CursorIcon {
+ match mouse_state {
+ MouseState::Url(_) | MouseState::MessageBarButton => CursorIcon::Hand,
+ MouseState::Text => CursorIcon::Text,
+ _ => CursorIcon::Default,
+ }
+ }
+}
+
+impl<'a, T: EventListener, A: ActionContext<T> + 'a> Processor<'a, T, A> {
+ pub fn new(ctx: A, config: &'a mut Config) -> Self {
+ Self { ctx, config, _phantom: Default::default() }
+ }
+
fn mouse_state(&mut self, point: Point, mods: ModifiersState) -> MouseState {
let mouse_mode =
TermMode::MOUSE_MOTION | TermMode::MOUSE_DRAG | TermMode::MOUSE_REPORT_CLICK;
@@ -458,9 +244,9 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
}
// Check for URL at point with required modifiers held
- if self.mouse_config.url.mods().relaxed_eq(mods)
+ if self.config.ui_config.mouse.url.mods().relaxed_eq(mods)
&& (!self.ctx.terminal().mode().intersects(mouse_mode) || mods.shift)
- && self.mouse_config.url.launcher.is_some()
+ && self.config.ui_config.mouse.url.launcher.is_some()
&& self.ctx.selection_is_empty()
&& self.ctx.mouse().left_button_state != ElementState::Pressed
{
@@ -638,14 +424,16 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
self.ctx.mouse_mut().click_state = match self.ctx.mouse().click_state {
ClickState::Click
- if !button_changed && elapsed < self.mouse_config.double_click.threshold =>
+ if !button_changed
+ && elapsed < self.config.ui_config.mouse.double_click.threshold =>
{
self.ctx.mouse_mut().block_url_launcher = true;
self.on_mouse_double_click(button, point);
ClickState::DoubleClick
}
ClickState::DoubleClick
- if !button_changed && elapsed < self.mouse_config.triple_click.threshold =>
+ if !button_changed
+ && elapsed < self.config.ui_config.mouse.triple_click.threshold =>
{
self.ctx.mouse_mut().block_url_launcher = true;
self.on_mouse_triple_click(button, point);
@@ -723,7 +511,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
return;
}
- if let Some(ref launcher) = self.mouse_config.url.launcher {
+ if let Some(ref launcher) = self.config.ui_config.mouse.url.launcher {
let mut args = launcher.args().to_vec();
args.push(self.ctx.terminal().url_to_string(url));
@@ -766,7 +554,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
let height = self.ctx.size_info().cell_height as i32;
// Make sure the new and deprecated setting are both allowed
- let faux_multiplier = self.scrolling_config.faux_multiplier() as usize;
+ let faux_multiplier = self.config.scrolling.faux_multiplier() as usize;
if self.ctx.terminal().mode().intersects(mouse_modes) {
self.ctx.mouse_mut().scroll_px += new_scroll_px;
@@ -794,7 +582,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
}
self.ctx.write_to_pty(content);
} else {
- let multiplier = i32::from(self.scrolling_config.multiplier());
+ let multiplier = i32::from(self.config.scrolling.multiplier());
self.ctx.mouse_mut().scroll_px += new_scroll_px * multiplier;
let lines = self.ctx.mouse().scroll_px / height;
@@ -887,7 +675,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
c.encode_utf8(&mut bytes[..]);
}
- if self.alt_send_esc
+ if self.config.alt_send_esc()
&& *self.ctx.received_count() == 0
&& self.ctx.modifiers().alt()
&& utf8_len == 1
@@ -898,6 +686,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
self.ctx.write_to_pty(bytes);
*self.ctx.received_count() += 1;
+ self.ctx.terminal_mut().dirty = false;
}
/// Attempt to find a binding and execute its action.
@@ -905,29 +694,26 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
/// The provided mode, mods, and key must match what is allowed by a binding
/// for its action to be executed.
fn process_key_bindings(&mut self, input: KeyboardInput) {
- let mode = *self.ctx.terminal().mode();
-
- *self.ctx.suppress_chars() = self
- .key_bindings
- .iter()
- .filter(|binding| {
- let key = match (binding.trigger, input.virtual_keycode) {
- (Key::Scancode(_), _) => Key::Scancode(input.scancode),
- (_, Some(key)) => Key::from_glutin_input(key),
- _ => return false,
- };
+ let mut suppress_chars = None;
- binding.is_triggered_by(mode, input.modifiers, &key, false)
- })
- .fold(None, |suppress_chars, binding| {
+ for binding in &self.config.ui_config.key_bindings {
+ let key = match (binding.trigger, input.virtual_keycode) {
+ (Key::Scancode(_), _) => Key::Scancode(input.scancode),
+ (_, Some(key)) => Key::from_glutin_input(key),
+ _ => continue,
+ };
+
+ if binding.is_triggered_by(*self.ctx.terminal().mode(), input.modifiers, &key, false) {
// Binding was triggered; run the action
binding.execute(&mut self.ctx, false);
// Don't suppress when there has been a `ReceiveChar` action
- Some(suppress_chars.unwrap_or(true) && binding.action != Action::ReceiveChar)
- })
- // Don't suppress char if no bindings were triggered
- .unwrap_or(false);
+ *suppress_chars.get_or_insert(true) &= binding.action != Action::ReceiveChar;
+ }
+ }
+
+ // Don't suppress char if no bindings were triggered
+ *self.ctx.suppress_chars() = suppress_chars.unwrap_or(false);
}
/// Attempt to find a binding and execute its action.
@@ -935,7 +721,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
/// The provided mode, mods, and key must match what is allowed by a binding
/// for its action to be executed.
fn process_mouse_bindings(&mut self, mods: ModifiersState, button: MouseButton) {
- for binding in self.mouse_bindings {
+ for binding in &self.config.ui_config.mouse_bindings {
if binding.is_triggered_by(*self.ctx.terminal().mode(), mods, &button, true) {
// binding was triggered; run the action
let mouse_mode = !mods.shift
@@ -951,12 +737,10 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
/// Return the message bar's message if there is some at the specified point
fn message_at_point(&mut self, point: Option<Point>) -> Option<Message> {
- if let (Some(point), Some(message)) =
- (point, self.ctx.terminal_mut().message_buffer_mut().message())
- {
- let size = self.ctx.size_info();
- if point.line.0 >= size.lines().saturating_sub(message.text(&size).len()) {
- return Some(message);
+ let size = &self.ctx.size_info();
+ if let (Some(point), Some(message)) = (point, self.ctx.message()) {
+ if point.line.0 >= size.lines().saturating_sub(message.text(size).len()) {
+ return Some(message.to_owned());
}
}
@@ -984,7 +768,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
if self.message_close_at_point(point, message) {
let mouse_state = self.mouse_state(point, mods);
self.update_mouse_cursor(mouse_state);
- self.ctx.terminal_mut().message_buffer_mut().pop();
+ self.ctx.pop_message();
}
self.ctx.clear_selection();
@@ -994,7 +778,7 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
/// Copy text selection.
fn copy_selection(&mut self) {
- if self.save_to_clipboard {
+ if self.config.selection.save_to_clipboard {
self.ctx.copy_selection(ClipboardType::Clipboard);
}
self.ctx.copy_selection(ClipboardType::Selection);
@@ -1002,13 +786,16 @@ impl<'a, A: ActionContext + 'a> Processor<'a, A> {
#[inline]
fn update_mouse_cursor(&mut self, mouse_state: MouseState) {
- let mouse_cursor = match mouse_state {
- MouseState::Url(_) | MouseState::MessageBarButton => MouseCursor::Hand,
- MouseState::Text => MouseCursor::Text,
- _ => MouseCursor::Default,
- };
+ self.ctx.window_mut().set_mouse_cursor(mouse_state.into());
+ }
- self.ctx.terminal_mut().set_mouse_cursor(mouse_cursor);
+ #[inline]
+ pub fn reset_mouse_cursor(&mut self) {
+ if let Some(point) = self.ctx.mouse_coords() {
+ let mods = self.ctx.modifiers().into();
+ let mouse_state = self.mouse_state(point, mods);
+ self.update_mouse_cursor(mouse_state);
+ }
}
}
@@ -1017,202 +804,30 @@ mod tests {
use std::borrow::Cow;
use std::time::Duration;
- use glutin::{ElementState, Event, ModifiersState, MouseButton, VirtualKeyCode, WindowEvent};
+ use glutin::event::{
+ ElementState, Event, ModifiersState, MouseButton, VirtualKeyCode, WindowEvent,
+ };
+
+ use alacritty_terminal::clipboard::{Clipboard, ClipboardType};
+ use alacritty_terminal::event::{Event as TerminalEvent, EventListener};
+ use alacritty_terminal::grid::Scroll;
+ use alacritty_terminal::index::{Point, Side};
+ use alacritty_terminal::message_bar::{Message, MessageBuffer};
+ use alacritty_terminal::selection::Selection;
+ use alacritty_terminal::term::{SizeInfo, Term, TermMode};
- use crate::clipboard::{Clipboard, ClipboardType};
- use crate::config::{self, ClickHandler, Config};
- use crate::event::{ClickState, Mouse, WindowChanges};
- use crate::grid::Scroll;
- use crate::index::{Point, Side};
- use crate::message_bar::MessageBuffer;
- use crate::selection::Selection;
- use crate::term::{SizeInfo, Term, TermMode};
+ use crate::config::{ClickHandler, Config};
+ use crate::event::{ClickState, Mouse};
+ use crate::window::Window;
use super::{Action, Binding, Modifiers, Processor};
const KEY: VirtualKeyCode = VirtualKeyCode::Key0;
- type MockBinding = Binding<usize>;
-
- impl Default for MockBinding {
- fn default() -> Self {
- Self {
- mods: Default::default(),
- action: Default::default(),
- mode: TermMode::empty(),
- notmode: TermMode::empty(),
- trigger: Default::default(),
- }
- }
- }
-
- #[test]
- fn binding_matches_itself() {
- let binding = MockBinding::default();
- let identical_binding = MockBinding::default();
+ struct MockEventProxy;
- assert!(binding.triggers_match(&identical_binding));
- assert!(identical_binding.triggers_match(&binding));
- }
-
- #[test]
- fn binding_matches_different_action() {
- let binding = MockBinding::default();
- let mut different_action = MockBinding::default();
- different_action.action = Action::ClearHistory;
-
- assert!(binding.triggers_match(&different_action));
- assert!(different_action.triggers_match(&binding));
- }
-
- #[test]
- fn mods_binding_requires_strict_match() {
- let mut superset_mods = MockBinding::default();
- superset_mods.mods = ModifiersState { alt: true, logo: true, ctrl: true, shift: true };
- let mut subset_mods = MockBinding::default();
- subset_mods.mods = ModifiersState { alt: true, logo: false, ctrl: false, shift: false };
-
- assert!(!superset_mods.triggers_match(&subset_mods));
- assert!(!subset_mods.triggers_match(&superset_mods));
- }
-
- #[test]
- fn binding_matches_identical_mode() {
- let mut b1 = MockBinding::default();
- b1.mode = TermMode::ALT_SCREEN;
- let mut b2 = MockBinding::default();
- b2.mode = TermMode::ALT_SCREEN;
-
- assert!(b1.triggers_match(&b2));
- }
-
- #[test]
- fn binding_without_mode_matches_any_mode() {
- let b1 = MockBinding::default();
- let mut b2 = MockBinding::default();
- b2.mode = TermMode::APP_KEYPAD;
- b2.notmode = TermMode::ALT_SCREEN;
-
- assert!(b1.triggers_match(&b2));
- }
-
- #[test]
- fn binding_with_mode_matches_empty_mode() {
- let mut b1 = MockBinding::default();
- b1.mode = TermMode::APP_KEYPAD;
- b1.notmode = TermMode::ALT_SCREEN;
- let b2 = MockBinding::default();
-
- assert!(b1.triggers_match(&b2));
- }
-
- #[test]
- fn binding_matches_superset_mode() {
- let mut b1 = MockBinding::default();
- b1.mode = TermMode::APP_KEYPAD;
- let mut b2 = MockBinding::default();
- b2.mode = TermMode::ALT_SCREEN | TermMode::APP_KEYPAD;
-
- assert!(b1.triggers_match(&b2));
- }
-
- #[test]
- fn binding_matches_subset_mode() {
- let mut b1 = MockBinding::default();
- b1.mode = TermMode::ALT_SCREEN | TermMode::APP_KEYPAD;
- let mut b2 = MockBinding::default();
- b2.mode = TermMode::APP_KEYPAD;
-
- assert!(b1.triggers_match(&b2));
- }
-
- #[test]
- fn binding_matches_partial_intersection() {
- let mut b1 = MockBinding::default();
- b1.mode = TermMode::ALT_SCREEN | TermMode::APP_KEYPAD;
- let mut b2 = MockBinding::default();
- b2.mode = TermMode::APP_KEYPAD | TermMode::APP_CURSOR;
-
- assert!(b1.triggers_match(&b2));
- }
-
- #[test]
- fn binding_mismatches_notmode() {
- let mut b1 = MockBinding::default();
- b1.mode = TermMode::ALT_SCREEN;
- let mut b2 = MockBinding::default();
- b2.notmode = TermMode::ALT_SCREEN;
-
- assert!(!b1.triggers_match(&b2));
- }
-
- #[test]
- fn binding_mismatches_unrelated() {
- let mut b1 = MockBinding::default();
- b1.mode = TermMode::ALT_SCREEN;
- let mut b2 = MockBinding::default();
- b2.mode = TermMode::APP_KEYPAD;
-
- assert!(!b1.triggers_match(&b2));
- }
-
- #[test]
- fn binding_trigger_input() {
- let mut binding = MockBinding::default();
- binding.trigger = 13;
-
- let mods = binding.mods;
- let mode = binding.mode;
-
- assert!(binding.is_triggered_by(mode, mods, &13, true));
- assert!(!binding.is_triggered_by(mode, mods, &32, true));
- }
-
- #[test]
- fn binding_trigger_mods() {
- let mut binding = MockBinding::default();
- binding.mods = ModifiersState { alt: true, logo: true, ctrl: false, shift: false };
-
- let superset_mods = ModifiersState { alt: true, logo: true, ctrl: true, shift: true };
- let subset_mods = ModifiersState { alt: false, logo: false, ctrl: false, shift: false };
-
- let t = binding.trigger;
- let mode = binding.mode;
-
- assert!(binding.is_triggered_by(mode, binding.mods, &t, true));
- assert!(binding.is_triggered_by(mode, binding.mods, &t, false));
-
- assert!(binding.is_triggered_by(mode, superset_mods, &t, true));
- assert!(!binding.is_triggered_by(mode, superset_mods, &t, false));
-
- assert!(!binding.is_triggered_by(mode, subset_mods, &t, true));
- assert!(!binding.is_triggered_by(mode, subset_mods, &t, false));
- }
-
- #[test]
- fn binding_trigger_modes() {
- let mut binding = MockBinding::default();
- binding.mode = TermMode::ALT_SCREEN;
-
- let t = binding.trigger;
- let mods = binding.mods;
-
- assert!(!binding.is_triggered_by(TermMode::INSERT, mods, &t, true));
- assert!(binding.is_triggered_by(TermMode::ALT_SCREEN, mods, &t, true));
- assert!(binding.is_triggered_by(TermMode::ALT_SCREEN | TermMode::INSERT, mods, &t, true));
- }
-
- #[test]
- fn binding_trigger_notmodes() {
- let mut binding = MockBinding::default();
- binding.notmode = TermMode::ALT_SCREEN;
-
- let t = binding.trigger;
- let mods = binding.mods;
-
- assert!(binding.is_triggered_by(TermMode::INSERT, mods, &t, true));
- assert!(!binding.is_triggered_by(TermMode::ALT_SCREEN, mods, &t, true));
- assert!(!binding.is_triggered_by(TermMode::ALT_SCREEN | TermMode::INSERT, mods, &t, true));
+ impl EventListener for MockEventProxy {
+ fn send_event(&self, _event: TerminalEvent) {}
}
#[derive(PartialEq)]
@@ -1222,19 +837,19 @@ mod tests {
None,
}
- struct ActionContext<'a> {
- pub terminal: &'a mut Term,
+ struct ActionContext<'a, T> {
+ pub terminal: &'a mut Term<T>,
pub selection: &'a mut Option<Selection>,
pub size_info: &'a SizeInfo,
pub mouse: &'a mut Mouse,
+ pub message_buffer: &'a mut MessageBuffer,
pub last_action: MultiClick,
pub received_count: usize,
pub suppress_chars: bool,
pub modifiers: Modifiers,
- pub window_changes: &'a mut WindowChanges,
}
- impl<'a> super::ActionContext for ActionContext<'a> {
+ impl<'a, T: EventListener> super::ActionContext<T> for ActionContext<'a, T> {
fn write_to_pty<B: Into<Cow<'static, [u8]>>>(&mut self, _val: B) {}
fn update_selection(&mut self, _point: Point, _side: Side) {}
@@ -1247,20 +862,17 @@ mod tests {
fn clear_selection(&mut self) {}
- fn hide_window(&mut self) {}
-
fn spawn_new_instance(&mut self) {}
- fn toggle_fullscreen(&mut self) {}
+ fn change_font_size(&mut self, _delta: f32) {}
- #[cfg(target_os = "macos")]
- fn toggle_simple_fullscreen(&mut self) {}
+ fn reset_font_size(&mut self) {}
- fn terminal(&self) -> &Term {
+ fn terminal(&self) -> &Term<T> {
&self.terminal
}
- fn terminal_mut(&mut self) -> &mut Term {
+ fn terminal_mut(&mut self) -> &mut Term<T> {
&mut self.terminal
}
@@ -1286,7 +898,14 @@ mod tests {
}
fn mouse_coords(&self) -> Option<Point> {
- self.terminal.pixels_to_coords(self.mouse.x as usize, self.mouse.y as usize)
+ let x = self.mouse.x as usize;
+ let y = self.mouse.y as usize;
+
+ if self.size_info.contains_point(x, y, true) {
+ Some(self.size_info.pixels_to_coords(x, y))
+ } else {
+ None
+ }
}
#[inline]
@@ -1310,6 +929,22 @@ mod tests {
fn modifiers(&mut self) -> &mut Modifiers {
&mut self.modifiers
}
+
+ fn window(&self) -> &Window {
+ unimplemented!();
+ }
+
+ fn window_mut(&mut self) -> &mut Window {
+ unimplemented!();
+ }
+
+ fn pop_message(&mut self) {
+ self.message_buffer.pop();
+ }
+
+ fn message(&self) -> Option<&Message> {
+ self.message_buffer.message()
+ }
}
macro_rules! test_clickstate {
@@ -1323,7 +958,18 @@ mod tests {
} => {
#[test]
fn $name() {
- let config = Config::default();
+ let mut cfg = Config::default();
+ cfg.ui_config.mouse = crate::config::Mouse {
+ double_click: ClickHandler {
+ threshold: Duration::from_millis(1000),
+ },
+ triple_click: ClickHandler {
+ threshold: Duration::from_millis(1000),
+ },
+ hide_when_typing: false,
+ url: Default::default(),
+ };
+
let size = SizeInfo {
width: 21.0,
height: 51.0,
@@ -1334,7 +980,7 @@ mod tests {
dpr: 1.0,
};
- let mut terminal = Term::new(&config, size, MessageBuffer::new(), Clipboard::new_nop());
+ let mut terminal = Term::new(&cfg, &size, Clipboard::new_nop(), MockEventProxy);
let mut mouse = Mouse::default();
mouse.click_state = $initial_state;
@@ -1342,6 +988,8 @@ mod tests {
let mut selection = None;
+ let mut message_buffer = MessageBuffer::new();
+
let context = ActionContext {
terminal: &mut terminal,
selection: &mut selection,
@@ -1350,28 +998,11 @@ mod tests {
last_action: MultiClick::None,
received_count: 0,
suppress_chars: false,
- modifiers: Default::default(),
- window_changes: &mut WindowChanges::default(),
+ modifiers: Modifiers::default(),
+ message_buffer: &mut message_buffer,
};
- let mut processor = Processor {
- ctx: context,
- mouse_config: &config::Mouse {
- double_click: ClickHandler {
- threshold: Duration::from_millis(1000),
- },
- triple_click: ClickHandler {
- threshold: Duration::from_millis(1000),
- },
- hide_when_typing: false,
- url: Default::default(),
- },
- scrolling_config: &config::Scrolling::default(),
- key_bindings: &config.key_bindings[..],
- mouse_bindings: &config.mouse_bindings[..],
- save_to_clipboard: config.selection.save_to_clipboard,
- alt_send_esc: config.alt_send_esc(),
- };
+ let mut processor = Processor::new(context, &mut cfg);
if let Event::WindowEvent { event: WindowEvent::MouseInput { state, button, modifiers, .. }, .. } = $input {
processor.mouse_input(state, button, modifiers);
@@ -1408,7 +1039,7 @@ mod tests {
name: single_click,
initial_state: ClickState::None,
initial_button: MouseButton::Other(0),
- input: Event::WindowEvent {
+ input: Event::<TerminalEvent>::WindowEvent {
event: WindowEvent::MouseInput {
state: ElementState::Pressed,
button: MouseButton::Left,
@@ -1425,7 +1056,7 @@ mod tests {
name: double_click,
initial_state: ClickState::Click,
initial_button: MouseButton::Left,
- input: Event::WindowEvent {
+ input: Event::<TerminalEvent>::WindowEvent {
event: WindowEvent::MouseInput {
state: ElementState::Pressed,
button: MouseButton::Left,
@@ -1442,7 +1073,7 @@ mod tests {
name: triple_click,
initial_state: ClickState::DoubleClick,
initial_button: MouseButton::Left,
- input: Event::WindowEvent {
+ input: Event::<TerminalEvent>::WindowEvent {
event: WindowEvent::MouseInput {
state: ElementState::Pressed,
button: MouseButton::Left,
@@ -1459,7 +1090,7 @@ mod tests {
name: multi_click_separate_buttons,
initial_state: ClickState::DoubleClick,
initial_button: MouseButton::Left,
- input: Event::WindowEvent {
+ input: Event::<TerminalEvent>::WindowEvent {
event: WindowEvent::MouseInput {
state: ElementState::Pressed,
button: MouseButton::Right,
diff --git a/alacritty/src/logging.rs b/alacritty/src/logging.rs
index d4cb70c5..d1c95e43 100644
--- a/alacritty/src/logging.rs
+++ b/alacritty/src/logging.rs
@@ -25,10 +25,11 @@ use std::process;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::{Arc, Mutex};
-use crossbeam_channel::Sender;
+use glutin::event_loop::EventLoopProxy;
use log::{self, Level};
use time;
+use alacritty_terminal::event::Event;
use alacritty_terminal::message_bar::Message;
use alacritty_terminal::term::color;
@@ -38,7 +39,7 @@ const ALACRITTY_LOG_ENV: &str = "ALACRITTY_LOG";
pub fn initialize(
options: &Options,
- message_tx: Sender<Message>,
+ event_proxy: EventLoopProxy<Event>,
) -> Result<Option<PathBuf>, log::SetLoggerError> {
log::set_max_level(options.log_level);
@@ -48,7 +49,7 @@ pub fn initialize(
::env_logger::try_init()?;
Ok(None)
} else {
- let logger = Logger::new(message_tx);
+ let logger = Logger::new(event_proxy);
let path = logger.file_path();
log::set_boxed_logger(Box::new(logger))?;
Ok(path)
@@ -58,15 +59,15 @@ pub fn initialize(
pub struct Logger {
logfile: Mutex<OnDemandLogFile>,
stdout: Mutex<LineWriter<Stdout>>,
- message_tx: Sender<Message>,
+ event_proxy: Mutex<EventLoopProxy<Event>>,
}
impl Logger {
- fn new(message_tx: Sender<Message>) -> Self {
+ fn new(event_proxy: EventLoopProxy<Event>) -> Self {
let logfile = Mutex::new(OnDemandLogFile::new());
let stdout = Mutex::new(LineWriter::new(io::stdout()));
- Logger { logfile, stdout, message_tx }
+ Logger { logfile, stdout, event_proxy: Mutex::new(event_proxy) }
}
fn file_path(&self) -> Option<PathBuf> {
@@ -122,9 +123,12 @@ impl log::Log for Logger {
_ => unreachable!(),
};
- let mut message = Message::new(msg, color);
- message.set_topic(record.file().unwrap_or("?").into());
- let _ = self.message_tx.send(message);
+ if let Ok(event_proxy) = self.event_proxy.lock() {
+ let mut message = Message::new(msg, color);
+ message.set_target(record.target().to_owned());
+
+ let _ = event_proxy.send_event(Event::Message(message));
+ }
}
}
diff --git a/alacritty/src/main.rs b/alacritty/src/main.rs
index 65313cbe..146709fd 100644
--- a/alacritty/src/main.rs
+++ b/alacritty/src/main.rs
@@ -25,7 +25,7 @@
#[cfg(target_os = "macos")]
use std::env;
use std::error::Error;
-use std::fs::{self, File};
+use std::fs;
use std::io::{self, Write};
#[cfg(not(windows))]
use std::os::unix::io::AsRawFd;
@@ -33,29 +33,35 @@ use std::sync::Arc;
#[cfg(target_os = "macos")]
use dirs;
+use glutin::event_loop::EventLoop as GlutinEventLoop;
use log::{error, info};
-use serde_json as json;
#[cfg(windows)]
use winapi::um::wincon::{AttachConsole, FreeConsole, ATTACH_PARENT_PROCESS};
use alacritty_terminal::clipboard::Clipboard;
-use alacritty_terminal::config::{Config, Monitor};
-use alacritty_terminal::display::Display;
+use alacritty_terminal::event::Event;
use alacritty_terminal::event_loop::{self, EventLoop, Msg};
#[cfg(target_os = "macos")]
use alacritty_terminal::locale;
use alacritty_terminal::message_bar::MessageBuffer;
use alacritty_terminal::panic;
use alacritty_terminal::sync::FairMutex;
-use alacritty_terminal::term::{cell::Cell, Term};
+use alacritty_terminal::term::Term;
use alacritty_terminal::tty;
-use alacritty_terminal::{die, event};
mod cli;
mod config;
+mod display;
+mod event;
+mod input;
mod logging;
+mod window;
use crate::cli::Options;
+use crate::config::monitor::Monitor;
+use crate::config::Config;
+use crate::display::Display;
+use crate::event::{EventProxy, Processor};
fn main() {
panic::attach_handler();
@@ -71,12 +77,12 @@ fn main() {
// Load command line options
let options = Options::new();
- // Setup storage for message UI
- let message_buffer = MessageBuffer::new();
+ // Setup glutin event loop
+ let window_event_loop = GlutinEventLoop::<Event>::with_user_event();
// Initialize the logger as soon as possible as to capture output from other subsystems
- let log_file =
- logging::initialize(&options, message_buffer.tx()).expect("Unable to initialize logger");
+ let log_file = logging::initialize(&options, window_event_loop.create_proxy())
+ .expect("Unable to initialize logger");
// Load configuration file
// If the file is a command line argument, we won't write a generated default file
@@ -107,8 +113,9 @@ fn main() {
let persistent_logging = config.persistent_logging();
// Run alacritty
- if let Err(err) = run(config, message_buffer) {
- die!("Alacritty encountered an unrecoverable error:\n\n\t{}\n", err);
+ if let Err(err) = run(window_event_loop, config) {
+ println!("Alacritty encountered an unrecoverable error:\n\n\t{}\n", err);
+ std::process::exit(1);
}
// Clean up logfile
@@ -123,7 +130,7 @@ fn main() {
///
/// Creates a window, the terminal state, pty, I/O event loop, input processor,
/// config change monitor, and runs the main display loop.
-fn run(config: Config, message_buffer: MessageBuffer) -> Result<(), Box<dyn Error>> {
+fn run(window_event_loop: GlutinEventLoop<Event>, config: Config) -> Result<(), Box<dyn Error>> {
info!("Welcome to Alacritty");
if let Some(config_path) = &config.config_path {
info!("Configuration loaded from {:?}", config_path.display());
@@ -132,17 +139,19 @@ fn run(config: Config, message_buffer: MessageBuffer) -> Result<(), Box<dyn Erro
// Set environment variables
tty::setup_env(&config);
- // Create a display.
+ let event_proxy = EventProxy::new(window_event_loop.create_proxy());
+
+ // Create a display
//
- // The display manages a window and can draw the terminal
- let mut display = Display::new(&config)?;
+ // The display manages a window and can draw the terminal.
+ let display = Display::new(&config, &window_event_loop)?;
- info!("PTY Dimensions: {:?} x {:?}", display.size().lines(), display.size().cols());
+ info!("PTY Dimensions: {:?} x {:?}", display.size_info.lines(), display.size_info.cols());
// Create new native clipboard
- #[cfg(not(any(target_os = "macos", target_os = "windows")))]
- let clipboard = Clipboard::new(display.get_wayland_display());
- #[cfg(any(target_os = "macos", target_os = "windows"))]
+ #[cfg(not(any(target_os = "macos", windows)))]
+ let clipboard = Clipboard::new(display.window.wayland_display());
+ #[cfg(any(target_os = "macos", windows))]
let clipboard = Clipboard::new();
// Create the terminal
@@ -150,28 +159,28 @@ fn run(config: Config, message_buffer: MessageBuffer) -> Result<(), Box<dyn Erro
// This object contains all of the state about what's being displayed. It's
// wrapped in a clonable mutex since both the I/O loop and display need to
// access it.
- let terminal = Term::new(&config, display.size().to_owned(), message_buffer, clipboard);
+ let terminal = Term::new(&config, &display.size_info, clipboard, event_proxy.clone());
let terminal = Arc::new(FairMutex::new(terminal));
- // Find the window ID for setting $WINDOWID
- let window_id = display.get_window_id();
-
// Create the pty
//
// The pty forks a process to run the shell on the slave side of the
// pseudoterminal. A file descriptor for the master side is retained for
// reading/writing to the shell.
- let pty = tty::new(&config, &display.size(), window_id);
+ #[cfg(not(any(target_os = "macos", windows)))]
+ let pty = tty::new(&config, &display.size_info, display.window.x11_window_id());
+ #[cfg(any(target_os = "macos", windows))]
+ let pty = tty::new(&config, &display.size_info, None);
- // Get a reference to something that we can resize
+ // Create PTY resize handle
//
// This exists because rust doesn't know the interface is thread-safe
// and we need to be able to resize the PTY from the main thread while the IO
// thread owns the EventedRW object.
#[cfg(windows)]
- let mut resize_handle = pty.resize_handle();
+ let resize_handle = pty.resize_handle();
#[cfg(not(windows))]
- let mut resize_handle = pty.fd.as_raw_fd();
+ let resize_handle = pty.fd.as_raw_fd();
// Create the pseudoterminal I/O loop
//
@@ -180,86 +189,45 @@ fn run(config: Config, message_buffer: MessageBuffer) -> Result<(), Box<dyn Erro
// synchronized since the I/O loop updates the state, and the display
// consumes it periodically.
let event_loop =
- EventLoop::new(Arc::clone(&terminal), display.notifier(), pty, config.debug.ref_test);
+ EventLoop::new(Arc::clone(&terminal), event_proxy.clone(), pty, config.debug.ref_test);
// The event loop channel allows write requests from the event processor
- // to be sent to the loop and ultimately written to the pty.
+ // to be sent to the pty loop and ultimately written to the pty.
let loop_tx = event_loop.channel();
- // Event processor
- //
- // Need the Rc<RefCell<_>> here since a ref is shared in the resize callback
- let mut processor = event::Processor::new(
- event_loop::Notifier(event_loop.channel()),
- display.resize_channel(),
- &config,
- display.size().to_owned(),
- );
-
// Create a config monitor when config was loaded from path
//
// The monitor watches the config file for changes and reloads it. Pending
// config changes are processed in the main loop.
- let config_monitor = if config.live_config_reload() {
- config.config_path.as_ref().map(|path| Monitor::new(path, display.notifier()))
- } else {
- None
- };
-
- // Kick off the I/O thread
- let _io_thread = event_loop.spawn(None);
-
- info!("Initialisation complete");
-
- // Main display loop
- loop {
- // Process input and window events
- let mut terminal_lock = processor.process_events(&terminal, display.window());
-
- // Handle config reloads
- if let Some(ref path) = config_monitor.as_ref().and_then(Monitor::pending) {
- // Clear old config messages from bar
- terminal_lock.message_buffer_mut().remove_topic(config::SOURCE_FILE_PATH);
-
- if let Ok(config) = config::reload_from(path) {
- display.update_config(&config);
- processor.update_config(&config);
- terminal_lock.update_config(&config);
- }
-
- terminal_lock.dirty = true;
- }
-
- // Begin shutdown if the flag was raised
- if terminal_lock.should_exit() || tty::process_should_exit() {
- break;
- }
+ if config.live_config_reload() {
+ config.config_path.as_ref().map(|path| Monitor::new(path, event_proxy.clone()));
+ }
- // Maybe draw the terminal
- if terminal_lock.needs_draw() {
- // Try to update the position of the input method editor
- #[cfg(not(windows))]
- display.update_ime_position(&terminal_lock);
+ // Setup storage for message UI
+ let message_buffer = MessageBuffer::new();
- // Handle pending resize events
- //
- // The second argument is a list of types that want to be notified
- // of display size changes.
- display.handle_resize(&mut terminal_lock, &config, &mut resize_handle, &mut processor);
+ // Event processor
+ //
+ // Need the Rc<RefCell<_>> here since a ref is shared in the resize callback
+ let mut processor = Processor::new(
+ event_loop::Notifier(loop_tx.clone()),
+ Box::new(resize_handle),
+ message_buffer,
+ config,
+ display,
+ );
- drop(terminal_lock);
+ // Kick off the I/O thread
+ let io_thread = event_loop.spawn();
- // Draw the current state of the terminal
- display.draw(&terminal, &config);
- }
- }
+ info!("Initialisation complete");
- // Write ref tests to disk
- if config.debug.ref_test {
- write_ref_test_results(&terminal.lock());
- }
+ // Start event loop and block until shutdown
+ processor.run(terminal, window_event_loop);
- loop_tx.send(Msg::Shutdown).expect("Error sending shutdown to event loop");
+ // Shutdown PTY parser event loop
+ loop_tx.send(Msg::Shutdown).expect("Error sending shutdown to pty event loop");
+ io_thread.join().expect("join io thread");
// FIXME patch notify library to have a shutdown method
// config_reloader.join().ok();
@@ -274,29 +242,3 @@ fn run(config: Config, message_buffer: MessageBuffer) -> Result<(), Box<dyn Erro
Ok(())
}
-
-// Write the ref test results to the disk
-fn write_ref_test_results(terminal: &Term) {
- // dump grid state
- let mut grid = terminal.grid().clone();
- grid.initialize_all(&Cell::default());
- grid.truncate();
-
- let serialized_grid = json::to_string(&grid).expect("serialize grid");
-
- let serialized_size = json::to_string(terminal.size_info()).expect("serialize size");
-
- let serialized_config = format!("{{\"history_size\":{}}}", grid.history_size());
-
- File::create("./grid.json")
- .and_then(|mut f| f.write_all(serialized_grid.as_bytes()))
- .expect("write grid.json");
-
- File::create("./size.json")
- .and_then(|mut f| f.write_all(serialized_size.as_bytes()))
- .expect("write size.json");
-
- File::create("./config.json")
- .and_then(|mut f| f.write_all(serialized_config.as_bytes()))
- .expect("write config.json");
-}
diff --git a/alacritty_terminal/src/window.rs b/alacritty/src/window.rs
index f18fda3a..4b5de2c9 100644
--- a/alacritty_terminal/src/window.rs
+++ b/alacritty/src/window.rs
@@ -14,42 +14,43 @@
use std::convert::From;
#[cfg(not(any(target_os = "macos", windows)))]
use std::ffi::c_void;
-use std::fmt::Display;
+use std::fmt;
-use glutin::dpi::{LogicalPosition, LogicalSize, PhysicalSize};
+use glutin::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize};
+use glutin::event_loop::EventLoop;
#[cfg(target_os = "macos")]
-use glutin::os::macos::WindowExt;
+use glutin::platform::macos::{RequestUserAttentionType, WindowBuilderExtMacOS, WindowExtMacOS};
#[cfg(not(any(target_os = "macos", windows)))]
-use glutin::os::unix::{EventsLoopExt, WindowExt};
+use glutin::platform::unix::{EventLoopWindowTargetExtUnix, WindowBuilderExtUnix, WindowExtUnix};
#[cfg(not(target_os = "macos"))]
-use glutin::Icon;
-#[cfg(not(any(target_os = "macos", windows)))]
-use glutin::Window as GlutinWindow;
-use glutin::{
- self, ContextBuilder, ControlFlow, Event, EventsLoop, MouseCursor, PossiblyCurrent,
- WindowBuilder,
-};
+use glutin::window::Icon;
+use glutin::window::{CursorIcon, Fullscreen, Window as GlutinWindow, WindowBuilder, WindowId};
+use glutin::{self, ContextBuilder, PossiblyCurrent, WindowedContext};
#[cfg(not(target_os = "macos"))]
use image::ImageFormat;
#[cfg(not(any(target_os = "macos", windows)))]
use x11_dl::xlib::{Display as XDisplay, PropModeReplace, XErrorEvent, Xlib};
-use crate::config::{Config, Decorations, StartupMode, WindowConfig};
-use crate::gl;
+use alacritty_terminal::config::{Decorations, StartupMode, WindowConfig, DEFAULT_NAME};
+use alacritty_terminal::event::Event;
+use alacritty_terminal::gl;
+use alacritty_terminal::term::{SizeInfo, Term};
+
+use crate::config::Config;
// It's required to be in this directory due to the `windows.rc` file
#[cfg(not(target_os = "macos"))]
static WINDOW_ICON: &[u8] = include_bytes!("../../extra/windows/alacritty.ico");
-/// Default Alacritty name, used for window title and class.
-pub const DEFAULT_NAME: &str = "Alacritty";
-
/// Window errors
#[derive(Debug)]
pub enum Error {
/// Error creating the window
ContextCreation(glutin::CreationError),
+ /// Error dealing with fonts
+ Font(font::Error),
+
/// Error manipulating the rendering context
Context(glutin::ContextError),
}
@@ -57,43 +58,12 @@ pub enum Error {
/// Result of fallible operations concerning a Window.
type Result<T> = ::std::result::Result<T, Error>;
-/// A window which can be used for displaying the terminal
-///
-/// Wraps the underlying windowing library to provide a stable API in Alacritty
-pub struct Window {
- event_loop: EventsLoop,
- windowed_context: glutin::WindowedContext<PossiblyCurrent>,
- mouse_visible: bool,
-
- /// Keep track of the current mouse cursor to avoid unnecessarily changing it
- current_mouse_cursor: MouseCursor,
-
- /// Whether or not the window is the focused window.
- pub is_focused: bool,
-}
-
-/// Threadsafe APIs for the window
-pub struct Proxy {
- inner: glutin::EventsLoopProxy,
-}
-
-/// Information about where the window is being displayed
-///
-/// Useful for subsystems like the font rasterized which depend on DPI and scale
-/// factor.
-pub struct DeviceProperties {
- /// Scale factor for pixels <-> points.
- ///
- /// This will be 1. on standard displays and may have a different value on
- /// hidpi displays.
- pub scale_factor: f64,
-}
-
impl ::std::error::Error for Error {
fn cause(&self) -> Option<&dyn (::std::error::Error)> {
match *self {
Error::ContextCreation(ref err) => Some(err),
Error::Context(ref err) => Some(err),
+ Error::Font(ref err) => Some(err),
}
}
@@ -101,15 +71,17 @@ impl ::std::error::Error for Error {
match *self {
Error::ContextCreation(ref _err) => "Error creating gl context",
Error::Context(ref _err) => "Error operating on render context",
+ Error::Font(ref err) => err.description(),
}
}
}
-impl Display for Error {
- fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
Error::ContextCreation(ref err) => write!(f, "Error creating GL context; {}", err),
Error::Context(ref err) => write!(f, "Error operating on render context; {}", err),
+ Error::Font(ref err) => err.fmt(f),
}
}
}
@@ -126,14 +98,20 @@ impl From<glutin::ContextError> for Error {
}
}
+impl From<font::Error> for Error {
+ fn from(val: font::Error) -> Error {
+ Error::Font(val)
+ }
+}
+
fn create_gl_window(
mut window: WindowBuilder,
- event_loop: &EventsLoop,
+ event_loop: &EventLoop<Event>,
srgb: bool,
dimensions: Option<LogicalSize>,
-) -> Result<glutin::WindowedContext<PossiblyCurrent>> {
+) -> Result<WindowedContext<PossiblyCurrent>> {
if let Some(dimensions) = dimensions {
- window = window.with_dimensions(dimensions);
+ window = window.with_inner_size(dimensions);
}
let windowed_context = ContextBuilder::new()
@@ -148,25 +126,33 @@ fn create_gl_window(
Ok(windowed_context)
}
+/// A window which can be used for displaying the terminal
+///
+/// Wraps the underlying windowing library to provide a stable API in Alacritty
+pub struct Window {
+ windowed_context: WindowedContext<PossiblyCurrent>,
+ current_mouse_cursor: CursorIcon,
+ mouse_visible: bool,
+}
+
impl Window {
/// Create a new window
///
/// This creates a window and fully initializes a window.
pub fn new(
- event_loop: EventsLoop,
+ event_loop: &EventLoop<Event>,
config: &Config,
- dimensions: Option<LogicalSize>,
+ logical: Option<LogicalSize>,
) -> Result<Window> {
let title = config.window.title.as_ref().map_or(DEFAULT_NAME, |t| t);
let window_builder = Window::get_platform_window(title, &config.window);
let windowed_context =
- create_gl_window(window_builder.clone(), &event_loop, false, dimensions)
- .or_else(|_| create_gl_window(window_builder, &event_loop, true, dimensions))?;
- let window = windowed_context.window();
+ create_gl_window(window_builder.clone(), &event_loop, false, logical)
+ .or_else(|_| create_gl_window(window_builder, &event_loop, true, logical))?;
// Text cursor
- window.set_cursor(MouseCursor::Text);
+ windowed_context.window().set_cursor_icon(CursorIcon::Text);
// 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 _);
@@ -176,80 +162,33 @@ impl Window {
{
if event_loop.is_x11() {
if let Some(parent_window_id) = config.window.embed {
- x_embed_window(window, parent_window_id);
+ x_embed_window(windowed_context.window(), parent_window_id);
}
}
}
- let window = Window {
- event_loop,
- current_mouse_cursor: MouseCursor::Default,
- windowed_context,
+ Ok(Window {
+ current_mouse_cursor: CursorIcon::Default,
mouse_visible: true,
- is_focused: false,
- };
-
- Ok(window)
- }
-
- /// Get some properties about the device
- ///
- /// Some window properties are provided since subsystems like font
- /// rasterization depend on DPI and scale factor.
- pub fn device_properties(&self) -> DeviceProperties {
- DeviceProperties { scale_factor: self.window().get_hidpi_factor() }
- }
-
- pub fn inner_size_pixels(&self) -> Option<LogicalSize> {
- self.window().get_inner_size()
+ windowed_context,
+ })
}
pub fn set_inner_size(&mut self, size: LogicalSize) {
self.window().set_inner_size(size);
}
- #[inline]
- pub fn hidpi_factor(&self) -> f64 {
- self.window().get_hidpi_factor()
- }
-
- #[inline]
- pub fn create_window_proxy(&self) -> Proxy {
- Proxy { inner: self.event_loop.create_proxy() }
- }
-
- #[inline]
- pub fn swap_buffers(&self) -> Result<()> {
- self.windowed_context.swap_buffers().map_err(From::from)
- }
-
- /// Poll for any available events
- #[inline]
- pub fn poll_events<F>(&mut self, func: F)
- where
- F: FnMut(Event),
- {
- self.event_loop.poll_events(func);
- }
-
- #[inline]
- pub fn resize(&self, size: PhysicalSize) {
- self.windowed_context.resize(size);
+ pub fn inner_size(&self) -> LogicalSize {
+ self.window().inner_size()
}
- /// Show window
- #[inline]
- pub fn show(&self) {
- self.window().show();
+ pub fn hidpi_factor(&self) -> f64 {
+ self.window().hidpi_factor()
}
- /// Block waiting for events
#[inline]
- pub fn wait_events<F>(&mut self, func: F)
- where
- F: FnMut(Event) -> ControlFlow,
- {
- self.event_loop.run_forever(func);
+ pub fn set_visible(&self, visibility: bool) {
+ self.window().set_visible(visibility);
}
/// Set the window title
@@ -259,10 +198,10 @@ impl Window {
}
#[inline]
- pub fn set_mouse_cursor(&mut self, cursor: MouseCursor) {
+ pub fn set_mouse_cursor(&mut self, cursor: CursorIcon) {
if cursor != self.current_mouse_cursor {
self.current_mouse_cursor = cursor;
- self.window().set_cursor(cursor);
+ self.window().set_cursor_icon(cursor);
}
}
@@ -270,27 +209,29 @@ impl Window {
pub fn set_mouse_visible(&mut self, visible: bool) {
if visible != self.mouse_visible {
self.mouse_visible = visible;
- self.window().hide_cursor(!visible);
+ self.window().set_cursor_visible(visible);
}
}
#[cfg(not(any(target_os = "macos", windows)))]
pub fn get_platform_window(title: &str, window_config: &WindowConfig) -> WindowBuilder {
- use glutin::os::unix::WindowBuilderExt;
-
let decorations = match window_config.decorations {
Decorations::None => false,
_ => true,
};
- let icon = Icon::from_bytes_with_format(WINDOW_ICON, ImageFormat::ICO);
+ let image = image::load_from_memory_with_format(WINDOW_ICON, ImageFormat::ICO)
+ .expect("loading icon")
+ .to_rgba();
+ let (width, height) = image.dimensions();
+ let icon = Icon::from_rgba(image.into_raw(), width, height);
let class = &window_config.class;
let mut builder = WindowBuilder::new()
.with_title(title)
- .with_visibility(false)
- .with_transparency(true)
+ .with_visible(false)
+ .with_transparent(true)
.with_decorations(decorations)
.with_maximized(window_config.startup_mode() == StartupMode::Maximized)
.with_window_icon(icon.ok())
@@ -313,25 +254,27 @@ impl Window {
_ => true,
};
- let icon = Icon::from_bytes_with_format(WINDOW_ICON, ImageFormat::ICO);
+ let image = image::load_from_memory_with_format(WINDOW_ICON, ImageFormat::ICO)
+ .expect("loading icon")
+ .to_rgba();
+ let (width, height) = image.dimensions();
+ let icon = Icon::from_rgba(image.into_raw(), width, height);
WindowBuilder::new()
.with_title(title)
- .with_visibility(cfg!(windows))
+ .with_visible(true)
.with_decorations(decorations)
- .with_transparency(true)
+ .with_transparent(true)
.with_maximized(window_config.startup_mode() == StartupMode::Maximized)
.with_window_icon(icon.ok())
}
#[cfg(target_os = "macos")]
pub fn get_platform_window(title: &str, window_config: &WindowConfig) -> WindowBuilder {
- use glutin::os::macos::WindowBuilderExt;
-
let window = WindowBuilder::new()
.with_title(title)
- .with_visibility(false)
- .with_transparency(true)
+ .with_visible(false)
+ .with_transparent(true)
.with_maximized(window_config.startup_mode() == StartupMode::Maximized);
match window_config.decorations {
@@ -356,76 +299,103 @@ impl Window {
#[cfg(target_os = "macos")]
pub fn set_urgent(&self, is_urgent: bool) {
- self.window().request_user_attention(is_urgent);
+ if !is_urgent {
+ return;
+ }
+
+ self.window().request_user_attention(RequestUserAttentionType::Critical);
}
#[cfg(windows)]
pub fn set_urgent(&self, _is_urgent: bool) {}
- pub fn set_ime_spot(&self, pos: LogicalPosition) {
- self.window().set_ime_spot(pos);
+ pub fn set_outer_position(&self, pos: LogicalPosition) {
+ self.window().set_outer_position(pos);
}
- pub fn set_position(&self, pos: LogicalPosition) {
- self.window().set_position(pos);
+ #[cfg(not(any(target_os = "macos", windows)))]
+ pub fn x11_window_id(&self) -> Option<usize> {
+ self.window().xlib_window().map(|xlib_window| xlib_window as usize)
}
- #[cfg(not(any(target_os = "macos", target_os = "windows")))]
- pub fn get_window_id(&self) -> Option<usize> {
- match self.window().get_xlib_window() {
- Some(xlib_window) => Some(xlib_window as usize),
- None => None,
- }
+ pub fn window_id(&self) -> WindowId {
+ self.window().id()
}
- #[cfg(not(any(target_os = "macos", target_os = "windows")))]
- pub fn is_x11(&self) -> bool {
- self.event_loop.is_x11()
+ #[cfg(not(any(target_os = "macos", windows)))]
+ pub fn set_maximized(&self, maximized: bool) {
+ self.window().set_maximized(maximized);
}
- #[cfg(any(target_os = "macos", target_os = "windows"))]
- pub fn get_window_id(&self) -> Option<usize> {
- None
+ /// Toggle the window's fullscreen state
+ pub fn toggle_fullscreen(&mut self) {
+ self.set_fullscreen(self.window().fullscreen().is_none());
}
- /// Hide the window
- pub fn hide(&self) {
- self.window().hide();
+ #[cfg(target_os = "macos")]
+ pub fn toggle_simple_fullscreen(&mut self) {
+ self.set_simple_fullscreen(!self.window().simple_fullscreen());
}
- /// Fullscreens the window on the current monitor.
- pub fn set_fullscreen(&self, fullscreen: bool) {
- let glutin_window = self.window();
+ pub fn set_fullscreen(&mut self, fullscreen: bool) {
+ #[cfg(macos)]
+ {
+ if self.window().simple_fullscreen() {
+ return;
+ }
+ }
+
if fullscreen {
- let current_monitor = glutin_window.get_current_monitor();
- glutin_window.set_fullscreen(Some(current_monitor));
+ let current_monitor = self.window().current_monitor();
+ self.window().set_fullscreen(Some(Fullscreen::Borderless(current_monitor)));
} else {
- glutin_window.set_fullscreen(None);
+ self.window().set_fullscreen(None);
}
}
- pub fn set_maximized(&self, maximized: bool) {
- self.window().set_maximized(maximized);
- }
-
#[cfg(target_os = "macos")]
- pub fn set_simple_fullscreen(&self, fullscreen: bool) {
- self.window().set_simple_fullscreen(fullscreen);
+ pub fn set_simple_fullscreen(&mut self, simple_fullscreen: bool) {
+ if self.window().fullscreen().is_some() {
+ return;
+ }
+
+ self.window().set_simple_fullscreen(simple_fullscreen);
}
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
- pub fn get_wayland_display(&self) -> Option<*mut c_void> {
- self.window().get_wayland_display()
+ pub fn wayland_display(&self) -> Option<*mut c_void> {
+ self.window().wayland_display()
}
- fn window(&self) -> &glutin::Window {
+ /// Adjust the IME editor position according to the new location of the cursor
+ #[cfg(not(windows))]
+ pub fn update_ime_position<T>(&mut self, terminal: &Term<T>, size_info: &SizeInfo) {
+ let point = terminal.cursor().point;
+ let SizeInfo { cell_width: cw, cell_height: ch, padding_x: px, padding_y: py, dpr, .. } =
+ size_info;
+
+ let nspot_x = f64::from(px + point.col.0 as f32 * cw);
+ let nspot_y = f64::from(py + (point.line.0 + 1) as f32 * ch);
+
+ self.window().set_ime_position(PhysicalPosition::from((nspot_x, nspot_y)).to_logical(*dpr));
+ }
+
+ pub fn swap_buffers(&self) {
+ self.windowed_context.swap_buffers().expect("swap buffers");
+ }
+
+ pub fn resize(&self, size: PhysicalSize) {
+ self.windowed_context.resize(size);
+ }
+
+ fn window(&self) -> &GlutinWindow {
self.windowed_context.window()
}
}
#[cfg(not(any(target_os = "macos", windows)))]
fn x_embed_window(window: &GlutinWindow, parent_id: u64) {
- let (xlib_display, xlib_window) = match (window.get_xlib_display(), window.get_xlib_window()) {
+ let (xlib_display, xlib_window) = match (window.xlib_display(), window.xlib_window()) {
(Some(display), Some(window)) => (display, window),
_ => return,
};
@@ -459,15 +429,6 @@ fn x_embed_window(window: &GlutinWindow, parent_id: u64) {
#[cfg(not(any(target_os = "macos", windows)))]
unsafe extern "C" fn xembed_error_handler(_: *mut XDisplay, _: *mut XErrorEvent) -> i32 {
- die!("Could not embed into specified window.");
-}
-
-impl Proxy {
- /// Wakes up the event loop of the window
- ///
- /// This is useful for triggering a draw when the renderer would otherwise
- /// be waiting on user input.
- pub fn wakeup_event_loop(&self) {
- self.inner.wakeup().unwrap();
- }
+ println!("Could not embed into specified window.");
+ std::process::exit(1);
}
diff --git a/alacritty_terminal/Cargo.toml b/alacritty_terminal/Cargo.toml
index 4b3b98ea..949cdad5 100644
--- a/alacritty_terminal/Cargo.toml
+++ b/alacritty_terminal/Cargo.toml
@@ -15,8 +15,7 @@ notify = "4"
bitflags = "1"
font = { path = "../font" }
parking_lot = "0.9"
-serde = "1"
-serde_derive = "1"
+serde = { version = "1", features = ["derive"] }
serde_yaml = "0.8"
vte = "0.3"
mio = "0.6"
@@ -24,12 +23,10 @@ mio-extras = "2"
log = "0.4"
fnv = "1"
unicode-width = "0.1"
-glutin = { version = "0.21.0", features = ["icon_loading"] }
base64 = "0.10.0"
static_assertions = "0.3.0"
terminfo = "0.6.1"
url = "2"
-crossbeam-channel = "0.3.8"
copypasta = { path = "../copypasta" }
rfind_url = "0.4.0"
@@ -37,9 +34,6 @@ rfind_url = "0.4.0"
nix = "0.14.1"
signal-hook = { version = "0.1", features = ["mio-support"] }
-[target.'cfg(not(any(target_os = "macos", windows)))'.dependencies]
-x11-dl = "2"
-
[target.'cfg(windows)'.dependencies]
winpty = { path = "../winpty" }
mio-named-pipes = "0.1"
@@ -49,9 +43,6 @@ winapi = { version = "0.3.7", features = ["impl-default", "winuser", "synchapi",
widestring = "0.4"
mio-anonymous-pipes = "0.1"
-[target.'cfg(not(target_os = "macos"))'.dependencies]
-image = "0.21.0"
-
[target.'cfg(target_os = "macos")'.dependencies]
objc = "0.2.2"
diff --git a/alacritty_terminal/src/ansi.rs b/alacritty_terminal/src/ansi.rs
index 3bdef32d..b34c1cd9 100644
--- a/alacritty_terminal/src/ansi.rs
+++ b/alacritty_terminal/src/ansi.rs
@@ -16,11 +16,13 @@
use std::io;
use std::str;
-use crate::index::{Column, Contains, Line};
use base64;
-use glutin::MouseCursor;
+use log::{debug, trace};
+use serde::{Deserialize, Serialize};
+
use vte;
+use crate::index::{Column, Contains, Line};
use crate::term::color::Rgb;
// Parse colors in XParseColor format
@@ -104,7 +106,7 @@ struct ProcessorState {
/// Processor creates a Performer when running advance and passes the Performer
/// to `vte::Parser`.
struct Performer<'a, H: Handler + TermInfo, W: io::Write> {
- _state: &'a mut ProcessorState,
+ state: &'a mut ProcessorState,
handler: &'a mut H,
writer: &'a mut W,
}
@@ -117,7 +119,7 @@ impl<'a, H: Handler + TermInfo + 'a, W: io::Write> Performer<'a, H, W> {
handler: &'b mut H,
writer: &'b mut W,
) -> Performer<'b, H, W> {
- Performer { _state: state, handler, writer }
+ Performer { state, handler, writer }
}
}
@@ -157,9 +159,6 @@ pub trait Handler {
/// OSC to set window title
fn set_title(&mut self, _: &str) {}
- /// Set the window's mouse cursor
- fn set_mouse_cursor(&mut self, _: MouseCursor) {}
-
/// Set the cursor style
fn set_cursor_style(&mut self, _: Option<CursorStyle>) {}
@@ -686,7 +685,7 @@ where
#[inline]
fn print(&mut self, c: char) {
self.handler.input(c);
- self._state.preceding_char = Some(c);
+ self.state.preceding_char = Some(c);
}
#[inline]
@@ -919,7 +918,7 @@ where
handler.move_up(Line(arg_or_default!(idx: 0, default: 1) as usize));
},
('b', None) => {
- if let Some(c) = self._state.preceding_char {
+ if let Some(c) = self.state.preceding_char {
for _ in 0..arg_or_default!(idx: 0, default: 1) {
handler.input(c);
}
diff --git a/alacritty_terminal/src/clipboard.rs b/alacritty_terminal/src/clipboard.rs
index dc826481..6f6a41be 100644
--- a/alacritty_terminal/src/clipboard.rs
+++ b/alacritty_terminal/src/clipboard.rs
@@ -15,6 +15,8 @@
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
use std::ffi::c_void;
+use log::{debug, warn};
+
use copypasta::nop_clipboard::NopClipboardContext;
#[cfg(not(any(target_os = "macos", target_os = "windows")))]
use copypasta::wayland_clipboard;
diff --git a/alacritty_terminal/src/config/colors.rs b/alacritty_terminal/src/config/colors.rs
index a9e7a6de..35c03684 100644
--- a/alacritty_terminal/src/config/colors.rs
+++ b/alacritty_terminal/src/config/colors.rs
@@ -1,10 +1,11 @@
+use log::error;
use serde::{Deserialize, Deserializer};
-use crate::config::failure_default;
+use crate::config::{failure_default, LOG_TARGET_CONFIG};
use crate::term::color::Rgb;
#[serde(default)]
-#[derive(Deserialize, Debug, Default, PartialEq, Eq)]
+#[derive(Deserialize, Clone, Debug, Default, PartialEq, Eq)]
pub struct Colors {
#[serde(deserialize_with = "failure_default")]
pub primary: PrimaryColors,
@@ -33,7 +34,7 @@ impl Colors {
}
#[serde(default)]
-#[derive(Deserialize, Default, Debug, PartialEq, Eq)]
+#[derive(Deserialize, Clone, Default, Debug, PartialEq, Eq)]
pub struct IndexedColor {
#[serde(deserialize_with = "deserialize_color_index")]
pub index: u8,
@@ -50,6 +51,7 @@ where
Ok(index) => {
if index < 16 {
error!(
+ target: LOG_TARGET_CONFIG,
"Problem with config: indexed_color's index is {}, but a value bigger than 15 \
was expected; ignoring setting",
index
@@ -62,7 +64,7 @@ where
}
},
Err(err) => {
- error!("Problem with config: {}; ignoring setting", err);
+ error!(target: LOG_TARGET_CONFIG, "Problem with config: {}; ignoring setting", err);
// Return value out of range to ignore this color
Ok(0)
@@ -89,7 +91,7 @@ pub struct SelectionColors {
}
#[serde(default)]
-#[derive(Deserialize, Debug, PartialEq, Eq)]
+#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct PrimaryColors {
#[serde(default = "default_background", deserialize_with = "failure_default")]
pub background: Rgb,
@@ -121,7 +123,7 @@ fn default_foreground() -> Rgb {
}
/// The 8-colors sections of config
-#[derive(Deserialize, Debug, PartialEq, Eq)]
+#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct AnsiColors {
#[serde(deserialize_with = "failure_default")]
pub black: Rgb,
@@ -141,7 +143,7 @@ pub struct AnsiColors {
pub white: Rgb,
}
-#[derive(Deserialize, Debug, PartialEq, Eq)]
+#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
struct NormalColors(AnsiColors);
impl Default for NormalColors {
@@ -159,7 +161,7 @@ impl Default for NormalColors {
}
}
-#[derive(Deserialize, Debug, PartialEq, Eq)]
+#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
struct BrightColors(AnsiColors);
impl Default for BrightColors {
diff --git a/alacritty_terminal/src/config/debug.rs b/alacritty_terminal/src/config/debug.rs
index b7d1144f..f3489693 100644
--- a/alacritty_terminal/src/config/debug.rs
+++ b/alacritty_terminal/src/config/debug.rs
@@ -1,7 +1,7 @@
-use log::LevelFilter;
-use serde::Deserializer;
+use log::{error, LevelFilter};
+use serde::{Deserialize, Deserializer};
-use crate::config::failure_default;
+use crate::config::{failure_default, LOG_TARGET_CONFIG};
/// Debugging options
#[serde(default)]
@@ -54,7 +54,10 @@ where
"debug" => LevelFilter::Debug,
"trace" => LevelFilter::Trace,
level => {
- error!("Problem with config: invalid log level {}; using level Warn", level);
+ error!(
+ target: LOG_TARGET_CONFIG,
+ "Problem with config: invalid log level {}; using level Warn", level
+ );
default_log_level()
},
})
diff --git a/alacritty_terminal/src/config/font.rs b/alacritty_terminal/src/config/font.rs
index 6148c982..a8a76c15 100644
--- a/alacritty_terminal/src/config/font.rs
+++ b/alacritty_terminal/src/config/font.rs
@@ -1,12 +1,13 @@
use std::fmt;
use font::Size;
+use log::error;
use serde::de::Visitor;
use serde::{Deserialize, Deserializer};
#[cfg(target_os = "macos")]
use crate::config::DefaultTrueBool;
-use crate::config::{failure_default, Delta};
+use crate::config::{failure_default, Delta, LOG_TARGET_CONFIG};
/// Font config
///
@@ -202,7 +203,12 @@ impl DeserializeSize for Size {
Ok(size) => Ok(size),
Err(err) => {
let size = default_font_size();
- error!("Problem with config: {}; using size {}", err, size.as_f32_pts());
+ error!(
+ target: LOG_TARGET_CONFIG,
+ "Problem with config: {}; using size {}",
+ err,
+ size.as_f32_pts()
+ );
Ok(size)
},
}
diff --git a/alacritty_terminal/src/config/mod.rs b/alacritty_terminal/src/config/mod.rs
index ac945e9b..cd900373 100644
--- a/alacritty_terminal/src/config/mod.rs
+++ b/alacritty_terminal/src/config/mod.rs
@@ -17,42 +17,38 @@ use std::collections::HashMap;
use std::fmt::Display;
use std::path::PathBuf;
+use log::error;
+use serde::de::DeserializeOwned;
use serde::{Deserialize, Deserializer};
use serde_yaml::Value;
-mod bindings;
mod colors;
mod debug;
mod font;
-mod monitor;
-mod mouse;
mod scrolling;
-#[cfg(test)]
-mod test;
mod visual_bell;
mod window;
use crate::ansi::{Color, CursorStyle, NamedColor};
-use crate::input::{Binding, KeyBinding, MouseBinding};
-pub use crate::config::bindings::Key;
pub use crate::config::colors::Colors;
pub use crate::config::debug::Debug;
pub use crate::config::font::{Font, FontDescription};
-pub use crate::config::monitor::Monitor;
-pub use crate::config::mouse::{ClickHandler, Mouse};
pub use crate::config::scrolling::Scrolling;
pub use crate::config::visual_bell::{VisualBellAnimation, VisualBellConfig};
-pub use crate::config::window::{Decorations, Dimensions, StartupMode, WindowConfig};
+pub use crate::config::window::{Decorations, Dimensions, StartupMode, WindowConfig, DEFAULT_NAME};
use crate::term::color::Rgb;
pub static DEFAULT_ALACRITTY_CONFIG: &str =
include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/../alacritty.yml"));
+pub const LOG_TARGET_CONFIG: &str = "alacritty_config";
const MAX_SCROLLBACK_LINES: u32 = 100_000;
+pub type MockConfig = Config<HashMap<String, serde_yaml::Value>>;
+
/// Top-level config type
#[derive(Debug, PartialEq, Deserialize)]
-pub struct Config {
+pub struct Config<T> {
/// Pixel padding
#[serde(default, deserialize_with = "failure_default")]
pub padding: Option<Delta<u8>>,
@@ -80,20 +76,9 @@ pub struct Config {
#[serde(default, deserialize_with = "failure_default")]
pub window: WindowConfig,
- /// Keybindings
- #[serde(default = "default_key_bindings", deserialize_with = "deserialize_key_bindings")]
- pub key_bindings: Vec<KeyBinding>,
-
- /// Bindings for the mouse
- #[serde(default = "default_mouse_bindings", deserialize_with = "deserialize_mouse_bindings")]
- pub mouse_bindings: Vec<MouseBinding>,
-
#[serde(default, deserialize_with = "failure_default")]
pub selection: Selection,
- #[serde(default, deserialize_with = "failure_default")]
- pub mouse: Mouse,
-
/// Path to a shell program to run on startup
#[serde(default, deserialize_with = "from_string_or_deserialize")]
pub shell: Option<Shell<'static>>,
@@ -144,6 +129,10 @@ pub struct Config {
#[serde(default, deserialize_with = "failure_default")]
pub debug: Debug,
+ /// Additional configuration options not directly required by the terminal
+ #[serde(flatten)]
+ pub ui_config: T,
+
// TODO: DEPRECATED
#[serde(default, deserialize_with = "failure_default")]
pub render_timer: Option<bool>,
@@ -153,13 +142,13 @@ pub struct Config {
pub persistent_logging: Option<bool>,
}
-impl Default for Config {
+impl<T: DeserializeOwned> Default for Config<T> {
fn default() -> Self {
serde_yaml::from_str(DEFAULT_ALACRITTY_CONFIG).expect("default config is invalid")
}
}
-impl Config {
+impl<T> Config<T> {
pub fn tabspaces(&self) -> usize {
self.tabspaces.0
}
@@ -236,49 +225,6 @@ impl Config {
}
}
-fn default_key_bindings() -> Vec<KeyBinding> {
- bindings::default_key_bindings()
-}
-
-fn default_mouse_bindings() -> Vec<MouseBinding> {
- bindings::default_mouse_bindings()
-}
-
-fn deserialize_key_bindings<'a, D>(deserializer: D) -> Result<Vec<KeyBinding>, D::Error>
-where
- D: Deserializer<'a>,
-{
- deserialize_bindings(deserializer, bindings::default_key_bindings())
-}
-
-fn deserialize_mouse_bindings<'a, D>(deserializer: D) -> Result<Vec<MouseBinding>, D::Error>
-where
- D: Deserializer<'a>,
-{
- deserialize_bindings(deserializer, bindings::default_mouse_bindings())
-}
-
-fn deserialize_bindings<'a, D, T>(
- deserializer: D,
- mut default: Vec<Binding<T>>,
-) -> Result<Vec<Binding<T>>, D::Error>
-where
- D: Deserializer<'a>,
- T: Copy + Eq + std::hash::Hash + std::fmt::Debug,
- Binding<T>: Deserialize<'a>,
-{
- let mut bindings: Vec<Binding<T>> = failure_default(deserializer)?;
-
- // Remove matching default bindings
- for binding in bindings.iter() {
- default.retain(|b| !b.triggers_match(binding));
- }
-
- bindings.extend(default);
-
- Ok(bindings)
-}
-
#[serde(default)]
#[derive(Deserialize, Default, Clone, Debug, PartialEq, Eq)]
pub struct Selection {
@@ -324,7 +270,7 @@ impl Cursor {
}
}
-#[derive(Debug, Deserialize, PartialEq, Eq)]
+#[derive(Clone, Debug, Deserialize, PartialEq, Eq)]
pub struct Shell<'a> {
pub program: Cow<'a, str>,
@@ -397,7 +343,7 @@ impl<'a> Deserialize<'a> for Alpha {
}
}
-#[derive(Deserialize, Debug, PartialEq, Eq)]
+#[derive(Deserialize, Copy, Clone, Debug, PartialEq, Eq)]
struct Tabspaces(usize);
impl Default for Tabspaces {
@@ -420,7 +366,7 @@ where
T: Default,
E: Display,
{
- error!("Problem with config: {}; using default value", err);
+ error!(target: LOG_TARGET_CONFIG, "Problem with config: {}; using default value", err);
T::default()
}
diff --git a/alacritty_terminal/src/config/scrolling.rs b/alacritty_terminal/src/config/scrolling.rs
index d62b102f..8471fcd7 100644
--- a/alacritty_terminal/src/config/scrolling.rs
+++ b/alacritty_terminal/src/config/scrolling.rs
@@ -1,6 +1,7 @@
+use log::error;
use serde::{Deserialize, Deserializer};
-use crate::config::{failure_default, MAX_SCROLLBACK_LINES};
+use crate::config::{failure_default, LOG_TARGET_CONFIG, MAX_SCROLLBACK_LINES};
/// Struct for scrolling related settings
#[serde(default)]
@@ -63,9 +64,11 @@ impl<'de> Deserialize<'de> for ScrollingHistory {
Ok(lines) => {
if lines > MAX_SCROLLBACK_LINES {
error!(
+ target: LOG_TARGET_CONFIG,
"Problem with config: scrollback size is {}, but expected a maximum of \
{}; using {1} instead",
- lines, MAX_SCROLLBACK_LINES,
+ lines,
+ MAX_SCROLLBACK_LINES,
);
Ok(ScrollingHistory(MAX_SCROLLBACK_LINES))
} else {
@@ -73,7 +76,10 @@ impl<'de> Deserialize<'de> for ScrollingHistory {
}
},
Err(err) => {
- error!("Problem with config: {}; using default value", err);
+ error!(
+ target: LOG_TARGET_CONFIG,
+ "Problem with config: {}; using default value", err
+ );
Ok(Default::default())
},
}
diff --git a/alacritty_terminal/src/config/visual_bell.rs b/alacritty_terminal/src/config/visual_bell.rs
index 3a31b24a..8981c929 100644
--- a/alacritty_terminal/src/config/visual_bell.rs
+++ b/alacritty_terminal/src/config/visual_bell.rs
@@ -1,10 +1,12 @@
use std::time::Duration;
+use serde::Deserialize;
+
use crate::config::failure_default;
use crate::term::color::Rgb;
#[serde(default)]
-#[derive(Debug, Deserialize, PartialEq, Eq)]
+#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct VisualBellConfig {
/// Visual bell animation function
#[serde(deserialize_with = "failure_default")]
diff --git a/alacritty_terminal/src/config/window.rs b/alacritty_terminal/src/config/window.rs
index 7ca90a5b..f470f936 100644
--- a/alacritty_terminal/src/config/window.rs
+++ b/alacritty_terminal/src/config/window.rs
@@ -1,8 +1,12 @@
+use serde::Deserialize;
+
use crate::config::{
failure_default, from_string_or_deserialize, option_explicit_none, Delta, FromString,
};
use crate::index::{Column, Line};
-use crate::window::DEFAULT_NAME;
+
+/// Default Alacritty name, used for window title and class.
+pub const DEFAULT_NAME: &str = "Alacritty";
#[serde(default)]
#[derive(Deserialize, Debug, Clone, Default, PartialEq, Eq)]
diff --git a/alacritty_terminal/src/cursor.rs b/alacritty_terminal/src/cursor.rs
index 93f2bd30..d1df14e2 100644
--- a/alacritty_terminal/src/cursor.rs
+++ b/alacritty_terminal/src/cursor.rs
@@ -16,6 +16,8 @@
use std::cmp;
+use serde::Deserialize;
+
use font::{Metrics, RasterizedGlyph};
use crate::ansi::CursorStyle;
diff --git a/alacritty_terminal/src/display.rs b/alacritty_terminal/src/display.rs
deleted file mode 100644
index bdd34460..00000000
--- a/alacritty_terminal/src/display.rs
+++ /dev/null
@@ -1,603 +0,0 @@
-// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-//! The display subsystem including window management, font rasterization, and
-//! GPU drawing.
-use std::f64;
-#[cfg(not(any(target_os = "macos", target_os = "windows")))]
-use std::ffi::c_void;
-use std::sync::mpsc;
-
-use glutin::dpi::{PhysicalPosition, PhysicalSize};
-use glutin::EventsLoop;
-use parking_lot::MutexGuard;
-
-use crate::config::{Config, StartupMode};
-use crate::index::Line;
-use crate::message_bar::Message;
-use crate::meter::Meter;
-use crate::renderer::rects::{RenderLines, RenderRect};
-use crate::renderer::{self, GlyphCache, QuadRenderer};
-use crate::sync::FairMutex;
-use crate::term::color::Rgb;
-use crate::term::{RenderableCell, SizeInfo, Term};
-use crate::window::{self, Window};
-use font::{self, Rasterize};
-
-#[derive(Debug)]
-pub enum Error {
- /// Error with window management
- Window(window::Error),
-
- /// Error dealing with fonts
- Font(font::Error),
-
- /// Error in renderer
- Render(renderer::Error),
-}
-
-impl ::std::error::Error for Error {
- fn cause(&self) -> Option<&dyn (::std::error::Error)> {
- match *self {
- Error::Window(ref err) => Some(err),
- Error::Font(ref err) => Some(err),
- Error::Render(ref err) => Some(err),
- }
- }
-
- fn description(&self) -> &str {
- match *self {
- Error::Window(ref err) => err.description(),
- Error::Font(ref err) => err.description(),
- Error::Render(ref err) => err.description(),
- }
- }
-}
-
-impl ::std::fmt::Display for Error {
- fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
- match *self {
- Error::Window(ref err) => err.fmt(f),
- Error::Font(ref err) => err.fmt(f),
- Error::Render(ref err) => err.fmt(f),
- }
- }
-}
-
-impl From<window::Error> for Error {
- fn from(val: window::Error) -> Error {
- Error::Window(val)
- }
-}
-
-impl From<font::Error> for Error {
- fn from(val: font::Error) -> Error {
- Error::Font(val)
- }
-}
-
-impl From<renderer::Error> for Error {
- fn from(val: renderer::Error) -> Error {
- Error::Render(val)
- }
-}
-
-/// The display wraps a window, font rasterizer, and GPU renderer
-pub struct Display {
- window: Window,
- renderer: QuadRenderer,
- glyph_cache: GlyphCache,
- render_timer: bool,
- rx: mpsc::Receiver<PhysicalSize>,
- tx: mpsc::Sender<PhysicalSize>,
- meter: Meter,
- font_size: font::Size,
- size_info: SizeInfo,
- last_message: Option<Message>,
-}
-
-/// Can wakeup the render loop from other threads
-pub struct Notifier(window::Proxy);
-
-/// Types that are interested in when the display is resized
-pub trait OnResize {
- fn on_resize(&mut self, size: &SizeInfo);
-}
-
-impl Notifier {
- pub fn notify(&self) {
- self.0.wakeup_event_loop();
- }
-}
-
-impl Display {
- pub fn notifier(&self) -> Notifier {
- Notifier(self.window.create_window_proxy())
- }
-
- pub fn update_config(&mut self, config: &Config) {
- self.render_timer = config.render_timer();
- }
-
- /// Get size info about the display
- pub fn size(&self) -> &SizeInfo {
- &self.size_info
- }
-
- pub fn new(config: &Config) -> Result<Display, Error> {
- // Extract some properties from config
- let render_timer = config.render_timer();
-
- // Guess DPR based on first monitor
- let event_loop = EventsLoop::new();
- let estimated_dpr =
- event_loop.get_available_monitors().next().map(|m| m.get_hidpi_factor()).unwrap_or(1.);
-
- // Guess the target window dimensions
- let metrics = GlyphCache::static_metrics(config, estimated_dpr as f32)?;
- let (cell_width, cell_height) = Self::compute_cell_size(config, &metrics);
- let dimensions = Self::calculate_dimensions(config, estimated_dpr, cell_width, cell_height);
-
- debug!("Estimated DPR: {}", estimated_dpr);
- debug!("Estimated Cell Size: {} x {}", cell_width, cell_height);
- debug!("Estimated Dimensions: {:?}", dimensions);
-
- // Create the window where Alacritty will be displayed
- let logical = dimensions.map(|d| PhysicalSize::new(d.0, d.1).to_logical(estimated_dpr));
- let mut window = Window::new(event_loop, &config, logical)?;
-
- let dpr = window.hidpi_factor();
- info!("Device pixel ratio: {}", dpr);
-
- // get window properties for initializing the other subsystems
- let mut viewport_size =
- window.inner_size_pixels().expect("glutin returns window size").to_physical(dpr);
-
- // Create renderer
- let mut renderer = QuadRenderer::new()?;
-
- let (glyph_cache, cell_width, cell_height) =
- Self::new_glyph_cache(dpr, &mut renderer, config)?;
-
- let mut padding_x = f64::from(config.window.padding.x) * dpr;
- let mut padding_y = f64::from(config.window.padding.y) * dpr;
-
- if let Some((width, height)) =
- Self::calculate_dimensions(config, dpr, cell_width, cell_height)
- {
- if dimensions == Some((width, height)) {
- info!("Estimated DPR correctly, skipping resize");
- } else {
- viewport_size = PhysicalSize::new(width, height);
- window.set_inner_size(viewport_size.to_logical(dpr));
- }
- } else if config.window.dynamic_padding {
- // Make sure additional padding is spread evenly
- let cw = f64::from(cell_width);
- let ch = f64::from(cell_height);
- padding_x = padding_x + (viewport_size.width - 2. * padding_x) % cw / 2.;
- padding_y = padding_y + (viewport_size.height - 2. * padding_y) % ch / 2.;
- }
-
- padding_x = padding_x.floor();
- padding_y = padding_y.floor();
-
- // Update OpenGL projection
- renderer.resize(viewport_size, padding_x as f32, padding_y as f32);
-
- info!("Cell Size: {} x {}", cell_width, cell_height);
- info!("Padding: {} x {}", padding_x, padding_y);
-
- let size_info = SizeInfo {
- dpr,
- width: viewport_size.width as f32,
- height: viewport_size.height as f32,
- cell_width: cell_width as f32,
- cell_height: cell_height as f32,
- padding_x: padding_x as f32,
- padding_y: padding_y as f32,
- };
-
- // Channel for resize events
- //
- // macOS has a callback for getting resize events, the channel is used
- // to queue resize events until the next draw call. Unfortunately, it
- // seems that the event loop is blocked until the window is done
- // resizing. If any drawing were to happen during a resize, it would
- // need to be in the callback.
- let (tx, rx) = mpsc::channel();
-
- // Clear screen
- let background_color = config.colors.primary.background;
- renderer.with_api(config, &size_info, |api| {
- api.clear(background_color);
- });
-
- // We should call `clear` when window is offscreen, so when `window.show()` happens it
- // would be with background color instead of uninitialized surface.
- window.swap_buffers()?;
-
- window.show();
-
- // Set window position
- //
- // TODO: replace `set_position` with `with_position` once available
- // Upstream issue: https://github.com/tomaka/winit/issues/806
- if let Some(position) = config.window.position {
- let physical = PhysicalPosition::from((position.x, position.y));
- let logical = physical.to_logical(window.hidpi_factor());
- window.set_position(logical);
- }
-
- #[allow(clippy::single_match)]
- match config.window.startup_mode() {
- StartupMode::Fullscreen => window.set_fullscreen(true),
- #[cfg(target_os = "macos")]
- StartupMode::SimpleFullscreen => window.set_simple_fullscreen(true),
- #[cfg(not(any(target_os = "macos", windows)))]
- StartupMode::Maximized if window.is_x11() => window.set_maximized(true),
- _ => (),
- }
-
- Ok(Display {
- window,
- renderer,
- glyph_cache,
- render_timer,
- tx,
- rx,
- meter: Meter::new(),
- font_size: config.font.size,
- size_info,
- last_message: None,
- })
- }
-
- fn calculate_dimensions(
- config: &Config,
- dpr: f64,
- cell_width: f32,
- cell_height: f32,
- ) -> Option<(f64, f64)> {
- let dimensions = config.window.dimensions;
-
- if dimensions.columns_u32() == 0
- || dimensions.lines_u32() == 0
- || config.window.startup_mode() != StartupMode::Windowed
- {
- return None;
- }
-
- let padding_x = f64::from(config.window.padding.x) * dpr;
- let padding_y = f64::from(config.window.padding.y) * dpr;
-
- // Calculate new size based on cols/lines specified in config
- let grid_width = cell_width as u32 * dimensions.columns_u32();
- let grid_height = cell_height as u32 * dimensions.lines_u32();
-
- let width = (f64::from(grid_width) + 2. * padding_x).floor();
- let height = (f64::from(grid_height) + 2. * padding_y).floor();
-
- Some((width, height))
- }
-
- fn new_glyph_cache(
- dpr: f64,
- renderer: &mut QuadRenderer,
- config: &Config,
- ) -> Result<(GlyphCache, f32, f32), Error> {
- let font = config.font.clone();
- let rasterizer = font::Rasterizer::new(dpr as f32, config.font.use_thin_strokes())?;
-
- // Initialize glyph cache
- let glyph_cache = {
- info!("Initializing glyph cache...");
- let init_start = ::std::time::Instant::now();
-
- let cache =
- renderer.with_loader(|mut api| GlyphCache::new(rasterizer, &font, &mut api))?;
-
- let stop = init_start.elapsed();
- let stop_f = stop.as_secs() as f64 + f64::from(stop.subsec_nanos()) / 1_000_000_000f64;
- info!("... finished initializing glyph cache in {}s", stop_f);
-
- cache
- };
-
- // Need font metrics to resize the window properly. This suggests to me the
- // font metrics should be computed before creating the window in the first
- // place so that a resize is not needed.
- let (cw, ch) = Self::compute_cell_size(config, &glyph_cache.font_metrics());
-
- Ok((glyph_cache, cw, ch))
- }
-
- pub fn update_glyph_cache(&mut self, config: &Config) {
- let cache = &mut self.glyph_cache;
- let dpr = self.size_info.dpr;
- let size = self.font_size;
-
- self.renderer.with_loader(|mut api| {
- let _ = cache.update_font_size(&config.font, size, dpr, &mut api);
- });
-
- let (cw, ch) = Self::compute_cell_size(config, &cache.font_metrics());
- self.size_info.cell_width = cw;
- self.size_info.cell_height = ch;
- }
-
- fn compute_cell_size(config: &Config, metrics: &font::Metrics) -> (f32, f32) {
- let offset_x = f64::from(config.font.offset.x);
- let offset_y = f64::from(config.font.offset.y);
- (
- f32::max(1., ((metrics.average_advance + offset_x) as f32).floor()),
- f32::max(1., ((metrics.line_height + offset_y) as f32).floor()),
- )
- }
-
- #[inline]
- pub fn resize_channel(&self) -> mpsc::Sender<PhysicalSize> {
- self.tx.clone()
- }
-
- pub fn window(&mut self) -> &mut Window {
- &mut self.window
- }
-
- /// Process pending resize events
- pub fn handle_resize(
- &mut self,
- terminal: &mut MutexGuard<'_, Term>,
- config: &Config,
- pty_resize_handle: &mut dyn OnResize,
- processor_resize_handle: &mut dyn OnResize,
- ) {
- let previous_cols = self.size_info.cols();
- let previous_lines = self.size_info.lines();
-
- // Resize events new_size and are handled outside the poll_events
- // iterator. This has the effect of coalescing multiple resize
- // events into one.
- let mut new_size = None;
-
- // Take most recent resize event, if any
- while let Ok(size) = self.rx.try_recv() {
- new_size = Some(size);
- }
-
- // Update the DPR
- let dpr = self.window.hidpi_factor();
-
- // Font size/DPI factor modification detected
- let font_changed =
- terminal.font_size != self.font_size || (dpr - self.size_info.dpr).abs() > f64::EPSILON;
-
- // Skip resize if nothing changed
- if let Some(new_size) = new_size {
- if !font_changed
- && (new_size.width - f64::from(self.size_info.width)).abs() < f64::EPSILON
- && (new_size.height - f64::from(self.size_info.height)).abs() < f64::EPSILON
- {
- return;
- }
- }
-
- // Message bar update detected
- let message_bar_changed = self.last_message != terminal.message_buffer_mut().message();
-
- if font_changed || message_bar_changed {
- if new_size == None {
- // Force a resize to refresh things
- new_size = Some(PhysicalSize::new(
- f64::from(self.size_info.width) / self.size_info.dpr * dpr,
- f64::from(self.size_info.height) / self.size_info.dpr * dpr,
- ));
- }
-
- self.font_size = terminal.font_size;
- self.last_message = terminal.message_buffer_mut().message();
- self.size_info.dpr = dpr;
- }
-
- if font_changed {
- self.update_glyph_cache(config);
- }
-
- if let Some(psize) = new_size.take() {
- let width = psize.width as f32;
- let height = psize.height as f32;
- let cell_width = self.size_info.cell_width;
- let cell_height = self.size_info.cell_height;
-
- self.size_info.width = width;
- self.size_info.height = height;
-
- let mut padding_x = f32::from(config.window.padding.x) * dpr as f32;
- let mut padding_y = f32::from(config.window.padding.y) * dpr as f32;
-
- if config.window.dynamic_padding {
- padding_x = padding_x + ((width - 2. * padding_x) % cell_width) / 2.;
- padding_y = padding_y + ((height - 2. * padding_y) % cell_height) / 2.;
- }
-
- self.size_info.padding_x = padding_x.floor();
- self.size_info.padding_y = padding_y.floor();
-
- let size = &self.size_info;
- terminal.resize(size);
- processor_resize_handle.on_resize(size);
-
- // Subtract message bar lines for pty size
- let mut pty_size = *size;
- if let Some(message) = terminal.message_buffer_mut().message() {
- pty_size.height -= pty_size.cell_height * message.text(&size).len() as f32;
- }
-
- if message_bar_changed
- || previous_cols != pty_size.cols()
- || previous_lines != pty_size.lines()
- {
- pty_resize_handle.on_resize(&pty_size);
- }
-
- self.window.resize(psize);
- self.renderer.resize(psize, self.size_info.padding_x, self.size_info.padding_y);
- }
- }
-
- /// Draw the screen
- ///
- /// A reference to Term whose state is being drawn must be provided.
- ///
- /// This call may block if vsync is enabled
- pub fn draw(&mut self, terminal: &FairMutex<Term>, config: &Config) {
- let mut terminal = terminal.lock();
- let size_info = *terminal.size_info();
- let visual_bell_intensity = terminal.visual_bell.intensity();
- let background_color = terminal.background_color();
- let metrics = self.glyph_cache.font_metrics();
-
- let window_focused = self.window.is_focused;
- let grid_cells: Vec<RenderableCell> =
- terminal.renderable_cells(config, window_focused).collect();
-
- // Get message from terminal to ignore modifications after lock is dropped
- let message_buffer = terminal.message_buffer_mut().message();
-
- // Clear dirty flag
- terminal.dirty = !terminal.visual_bell.completed();
-
- if let Some(title) = terminal.get_next_title() {
- self.window.set_title(&title);
- }
-
- if let Some(mouse_cursor) = terminal.get_next_mouse_cursor() {
- self.window.set_mouse_cursor(mouse_cursor);
- }
-
- if let Some(is_urgent) = terminal.next_is_urgent.take() {
- // We don't need to set the urgent flag if we already have the
- // user's attention.
- if !is_urgent || !self.window.is_focused {
- self.window.set_urgent(is_urgent);
- }
- }
-
- // Clear when terminal mutex isn't held. Mesa for
- // some reason takes a long time to call glClear(). The driver descends
- // into xcb_connect_to_fd() which ends up calling __poll_nocancel()
- // which blocks for a while.
- //
- // By keeping this outside of the critical region, the Mesa bug is
- // worked around to some extent. Since this doesn't actually address the
- // issue of glClear being slow, less time is available for input
- // handling and rendering.
- drop(terminal);
-
- self.renderer.with_api(config, &size_info, |api| {
- api.clear(background_color);
- });
-
- {
- let glyph_cache = &mut self.glyph_cache;
- let mut lines = RenderLines::new();
-
- // Draw grid
- {
- let _sampler = self.meter.sampler();
-
- self.renderer.with_api(config, &size_info, |mut api| {
- // Iterate over all non-empty cells in the grid
- for cell in grid_cells {
- // Update underline/strikeout
- lines.update(&cell);
-
- // Draw the cell
- api.render_cell(cell, glyph_cache);
- }
- });
- }
-
- let mut rects = lines.into_rects(&metrics, &size_info);
-
- if let Some(message) = message_buffer {
- let text = message.text(&size_info);
-
- // Create a new rectangle for the background
- let start_line = size_info.lines().0 - text.len();
- let y = size_info.padding_y + size_info.cell_height * start_line as f32;
- rects.push(RenderRect::new(
- 0.,
- y,
- size_info.width,
- size_info.height - y,
- message.color(),
- ));
-
- // Draw rectangles including the new background
- self.renderer.draw_rects(config, &size_info, visual_bell_intensity, rects);
-
- // Relay messages to the user
- let mut offset = 1;
- for message_text in text.iter().rev() {
- self.renderer.with_api(config, &size_info, |mut api| {
- api.render_string(
- &message_text,
- Line(size_info.lines().saturating_sub(offset)),
- glyph_cache,
- None,
- );
- });
- offset += 1;
- }
- } else {
- // Draw rectangles
- self.renderer.draw_rects(config, &size_info, visual_bell_intensity, rects);
- }
-
- // Draw render timer
- if self.render_timer {
- let timing = format!("{:.3} usec", self.meter.average());
- let color = Rgb { r: 0xd5, g: 0x4e, b: 0x53 };
- self.renderer.with_api(config, &size_info, |mut api| {
- api.render_string(&timing[..], size_info.lines() - 2, glyph_cache, Some(color));
- });
- }
- }
-
- self.window.swap_buffers().expect("swap buffers");
- }
-
- pub fn get_window_id(&self) -> Option<usize> {
- self.window.get_window_id()
- }
-
- /// Adjust the IME editor position according to the new location of the cursor
- pub fn update_ime_position(&mut self, terminal: &Term) {
- let point = terminal.cursor().point;
- let SizeInfo { cell_width: cw, cell_height: ch, padding_x: px, padding_y: py, .. } =
- *terminal.size_info();
-
- let dpr = self.window().hidpi_factor();
- let nspot_x = f64::from(px + point.col.0 as f32 * cw);
- let nspot_y = f64::from(py + (point.line.0 + 1) as f32 * ch);
-
- self.window().set_ime_spot(PhysicalPosition::from((nspot_x, nspot_y)).to_logical(dpr));
- }
-
- #[cfg(not(any(target_os = "macos", target_os = "windows")))]
- pub fn get_wayland_display(&self) -> Option<*mut c_void> {
- self.window.get_wayland_display()
- }
-}
diff --git a/alacritty_terminal/src/event.rs b/alacritty_terminal/src/event.rs
index 9d2aa78c..2d43e9dd 100644
--- a/alacritty_terminal/src/event.rs
+++ b/alacritty_terminal/src/event.rs
@@ -1,28 +1,19 @@
-//! Process window events
use std::borrow::Cow;
-use std::env;
-#[cfg(unix)]
-use std::fs;
-use std::sync::mpsc;
-use std::time::Instant;
+use std::path::PathBuf;
-use glutin::dpi::PhysicalSize;
-use glutin::{self, ElementState, Event, MouseButton};
-use parking_lot::MutexGuard;
+use crate::message_bar::Message;
+use crate::term::SizeInfo;
-use crate::clipboard::ClipboardType;
-use crate::config::{self, Config, StartupMode};
-use crate::display::OnResize;
-use crate::grid::Scroll;
-use crate::index::{Column, Line, Point, Side};
-use crate::input::{self, KeyBinding, Modifiers, MouseBinding};
-use crate::selection::Selection;
-use crate::sync::FairMutex;
-use crate::term::{SizeInfo, Term};
-#[cfg(unix)]
-use crate::tty;
-use crate::util::{limit, start_daemon};
-use crate::window::Window;
+#[derive(Clone, Debug, PartialEq)]
+pub enum Event {
+ ConfigReload(PathBuf),
+ MouseCursorDirty,
+ Message(Message),
+ Title(String),
+ Wakeup,
+ Urgent,
+ Exit,
+}
/// Byte sequences are sent to a `Notify` in response to some events
pub trait Notify {
@@ -32,526 +23,12 @@ pub trait Notify {
fn notify<B: Into<Cow<'static, [u8]>>>(&mut self, _: B);
}
-pub struct ActionContext<'a, N> {
- pub notifier: &'a mut N,
- pub terminal: &'a mut Term,
- pub size_info: &'a mut SizeInfo,
- pub mouse: &'a mut Mouse,
- pub received_count: &'a mut usize,
- pub suppress_chars: &'a mut bool,
- pub modifiers: &'a mut Modifiers,
- pub window_changes: &'a mut WindowChanges,
+/// Types that are interested in when the display is resized
+pub trait OnResize {
+ fn on_resize(&mut self, size: &SizeInfo);
}
-impl<'a, N: Notify + 'a> input::ActionContext for ActionContext<'a, N> {
- fn write_to_pty<B: Into<Cow<'static, [u8]>>>(&mut self, val: B) {
- self.notifier.notify(val);
- }
-
- fn size_info(&self) -> SizeInfo {
- *self.size_info
- }
-
- fn scroll(&mut self, scroll: Scroll) {
- self.terminal.scroll_display(scroll);
-
- if let ElementState::Pressed = self.mouse().left_button_state {
- let (x, y) = (self.mouse().x, self.mouse().y);
- let size_info = self.size_info();
- let point = size_info.pixels_to_coords(x, y);
- let cell_side = self.mouse().cell_side;
- self.update_selection(Point { line: point.line, col: point.col }, cell_side);
- }
- }
-
- fn copy_selection(&mut self, ty: ClipboardType) {
- if let Some(selected) = self.terminal.selection_to_string() {
- if !selected.is_empty() {
- self.terminal.clipboard().store(ty, selected);
- }
- }
- }
-
- fn selection_is_empty(&self) -> bool {
- self.terminal.selection().as_ref().map(Selection::is_empty).unwrap_or(true)
- }
-
- fn clear_selection(&mut self) {
- *self.terminal.selection_mut() = None;
- self.terminal.dirty = true;
- }
-
- fn update_selection(&mut self, point: Point, side: Side) {
- let point = self.terminal.visible_to_buffer(point);
-
- // Update selection if one exists
- if let Some(ref mut selection) = self.terminal.selection_mut() {
- selection.update(point, side);
- }
-
- self.terminal.dirty = true;
- }
-
- fn simple_selection(&mut self, point: Point, side: Side) {
- let point = self.terminal.visible_to_buffer(point);
- *self.terminal.selection_mut() = Some(Selection::simple(point, side));
- self.terminal.dirty = true;
- }
-
- fn block_selection(&mut self, point: Point, side: Side) {
- let point = self.terminal.visible_to_buffer(point);
- *self.terminal.selection_mut() = Some(Selection::block(point, side));
- self.terminal.dirty = true;
- }
-
- fn semantic_selection(&mut self, point: Point) {
- let point = self.terminal.visible_to_buffer(point);
- *self.terminal.selection_mut() = Some(Selection::semantic(point));
- self.terminal.dirty = true;
- }
-
- fn line_selection(&mut self, point: Point) {
- let point = self.terminal.visible_to_buffer(point);
- *self.terminal.selection_mut() = Some(Selection::lines(point));
- self.terminal.dirty = true;
- }
-
- fn mouse_coords(&self) -> Option<Point> {
- self.terminal.pixels_to_coords(self.mouse.x as usize, self.mouse.y as usize)
- }
-
- #[inline]
- fn mouse_mut(&mut self) -> &mut Mouse {
- self.mouse
- }
-
- #[inline]
- fn mouse(&self) -> &Mouse {
- self.mouse
- }
-
- #[inline]
- fn received_count(&mut self) -> &mut usize {
- &mut self.received_count
- }
-
- #[inline]
- fn suppress_chars(&mut self) -> &mut bool {
- &mut self.suppress_chars
- }
-
- #[inline]
- fn modifiers(&mut self) -> &mut Modifiers {
- &mut self.modifiers
- }
-
- #[inline]
- fn hide_window(&mut self) {
- self.window_changes.hide = true;
- }
-
- #[inline]
- fn terminal(&self) -> &Term {
- self.terminal
- }
-
- #[inline]
- fn terminal_mut(&mut self) -> &mut Term {
- self.terminal
- }
-
- fn spawn_new_instance(&mut self) {
- let alacritty = env::args().next().unwrap();
-
- #[cfg(unix)]
- let args = {
- #[cfg(not(target_os = "freebsd"))]
- let proc_prefix = "";
- #[cfg(target_os = "freebsd")]
- let proc_prefix = "/compat/linux";
- let link_path = format!("{}/proc/{}/cwd", proc_prefix, tty::child_pid());
- if let Ok(path) = fs::read_link(link_path) {
- vec!["--working-directory".into(), path]
- } else {
- Vec::new()
- }
- };
- #[cfg(not(unix))]
- let args: Vec<String> = Vec::new();
-
- match start_daemon(&alacritty, &args) {
- Ok(_) => debug!("Started new Alacritty process: {} {:?}", alacritty, args),
- Err(_) => warn!("Unable to start new Alacritty process: {} {:?}", alacritty, args),
- }
- }
-
- fn toggle_fullscreen(&mut self) {
- self.window_changes.toggle_fullscreen();
- }
-
- #[cfg(target_os = "macos")]
- fn toggle_simple_fullscreen(&mut self) {
- self.window_changes.toggle_simple_fullscreen()
- }
-}
-
-/// The ActionContext can't really have direct access to the Window
-/// with the current design. Event handlers that want to change the
-/// window must set these flags instead. The processor will trigger
-/// the actual changes.
-#[derive(Default)]
-pub struct WindowChanges {
- pub hide: bool,
- pub toggle_fullscreen: bool,
- #[cfg(target_os = "macos")]
- pub toggle_simple_fullscreen: bool,
-}
-
-impl WindowChanges {
- fn clear(&mut self) {
- *self = WindowChanges::default();
- }
-
- fn toggle_fullscreen(&mut self) {
- self.toggle_fullscreen = !self.toggle_fullscreen;
- }
-
- #[cfg(target_os = "macos")]
- fn toggle_simple_fullscreen(&mut self) {
- self.toggle_simple_fullscreen = !self.toggle_simple_fullscreen;
- }
-}
-
-pub enum ClickState {
- None,
- Click,
- DoubleClick,
- TripleClick,
-}
-
-/// State of the mouse
-pub struct Mouse {
- pub x: usize,
- pub y: usize,
- pub left_button_state: ElementState,
- pub middle_button_state: ElementState,
- pub right_button_state: ElementState,
- pub last_click_timestamp: Instant,
- pub click_state: ClickState,
- pub scroll_px: i32,
- pub line: Line,
- pub column: Column,
- pub cell_side: Side,
- pub lines_scrolled: f32,
- pub block_url_launcher: bool,
- pub last_button: MouseButton,
-}
-
-impl Default for Mouse {
- fn default() -> Mouse {
- Mouse {
- x: 0,
- y: 0,
- last_click_timestamp: Instant::now(),
- left_button_state: ElementState::Released,
- middle_button_state: ElementState::Released,
- right_button_state: ElementState::Released,
- click_state: ClickState::None,
- scroll_px: 0,
- line: Line(0),
- column: Column(0),
- cell_side: Side::Left,
- lines_scrolled: 0.0,
- block_url_launcher: false,
- last_button: MouseButton::Other(0),
- }
- }
-}
-
-/// The event processor
-///
-/// Stores some state from received events and dispatches actions when they are
-/// triggered.
-pub struct Processor<N> {
- key_bindings: Vec<KeyBinding>,
- mouse_bindings: Vec<MouseBinding>,
- mouse_config: config::Mouse,
- scrolling_config: config::Scrolling,
- print_events: bool,
- wait_for_event: bool,
- notifier: N,
- mouse: Mouse,
- resize_tx: mpsc::Sender<PhysicalSize>,
- size_info: SizeInfo,
- hide_mouse_when_typing: bool,
- hide_mouse: bool,
- received_count: usize,
- suppress_chars: bool,
- modifiers: Modifiers,
- pending_events: Vec<Event>,
- window_changes: WindowChanges,
- save_to_clipboard: bool,
- alt_send_esc: bool,
- is_fullscreen: bool,
- is_simple_fullscreen: bool,
-}
-
-/// Notify that the terminal was resized
-///
-/// Currently this just forwards the notice to the input processor.
-impl<N> OnResize for Processor<N> {
- fn on_resize(&mut self, size: &SizeInfo) {
- self.size_info = size.to_owned();
- }
-}
-
-impl<N: Notify> Processor<N> {
- /// Create a new event processor
- ///
- /// Takes a writer which is expected to be hooked up to the write end of a
- /// pty.
- pub fn new(
- notifier: N,
- resize_tx: mpsc::Sender<PhysicalSize>,
- config: &Config,
- size_info: SizeInfo,
- ) -> Processor<N> {
- Processor {
- key_bindings: config.key_bindings.to_vec(),
- mouse_bindings: config.mouse_bindings.to_vec(),
- mouse_config: config.mouse.to_owned(),
- scrolling_config: config.scrolling,
- print_events: config.debug.print_events,
- wait_for_event: true,
- notifier,
- resize_tx,
- mouse: Default::default(),
- size_info,
- hide_mouse_when_typing: config.mouse.hide_when_typing,
- hide_mouse: false,
- received_count: 0,
- suppress_chars: false,
- modifiers: Default::default(),
- pending_events: Vec::with_capacity(4),
- window_changes: Default::default(),
- save_to_clipboard: config.selection.save_to_clipboard,
- alt_send_esc: config.alt_send_esc(),
- is_fullscreen: config.window.startup_mode() == StartupMode::Fullscreen,
- #[cfg(target_os = "macos")]
- is_simple_fullscreen: config.window.startup_mode() == StartupMode::SimpleFullscreen,
- #[cfg(not(target_os = "macos"))]
- is_simple_fullscreen: false,
- }
- }
-
- /// Handle events from glutin
- ///
- /// Doesn't take self mutably due to borrow checking. Kinda uggo but w/e.
- fn handle_event<'a>(
- processor: &mut input::Processor<'a, ActionContext<'a, N>>,
- event: Event,
- resize_tx: &mpsc::Sender<PhysicalSize>,
- hide_mouse: &mut bool,
- window_is_focused: &mut bool,
- ) {
- match event {
- // Pass on device events
- Event::DeviceEvent { .. } | Event::Suspended { .. } => (),
- Event::WindowEvent { event, .. } => {
- use glutin::WindowEvent::*;
- match event {
- CloseRequested => processor.ctx.terminal.exit(),
- Resized(lsize) => {
- // Resize events are emitted via glutin/winit with logical sizes
- // However the terminal, window and renderer use physical sizes
- // so a conversion must be done here
- resize_tx
- .send(lsize.to_physical(processor.ctx.size_info.dpr))
- .expect("send new size");
- processor.ctx.terminal.dirty = true;
- },
- KeyboardInput { input, .. } => {
- processor.process_key(input);
- if input.state == ElementState::Pressed {
- // Hide cursor while typing
- *hide_mouse = true;
- }
- },
- ReceivedCharacter(c) => {
- processor.received_char(c);
- },
- MouseInput { state, button, modifiers, .. } => {
- if !cfg!(target_os = "macos") || *window_is_focused {
- *hide_mouse = false;
- processor.mouse_input(state, button, modifiers);
- processor.ctx.terminal.dirty = true;
- }
- },
- CursorMoved { position: lpos, modifiers, .. } => {
- let (x, y) = lpos.to_physical(processor.ctx.size_info.dpr).into();
- let x: i32 = limit(x, 0, processor.ctx.size_info.width as i32);
- let y: i32 = limit(y, 0, processor.ctx.size_info.height as i32);
-
- *hide_mouse = false;
- processor.mouse_moved(x as usize, y as usize, modifiers);
- },
- MouseWheel { delta, phase, modifiers, .. } => {
- *hide_mouse = false;
- processor.on_mouse_wheel(delta, phase, modifiers);
- },
- Refresh => {
- processor.ctx.terminal.dirty = true;
- },
- Focused(is_focused) => {
- *window_is_focused = is_focused;
-
- if is_focused {
- processor.ctx.terminal.next_is_urgent = Some(false);
- processor.ctx.terminal.dirty = true;
- } else {
- processor.ctx.terminal.dirty = true;
- *hide_mouse = false;
- }
-
- processor.on_focus_change(is_focused);
- },
- DroppedFile(path) => {
- use crate::input::ActionContext;
- let path: String = path.to_string_lossy().into();
- processor.ctx.write_to_pty(path.into_bytes());
- },
- HiDpiFactorChanged(new_dpr) => {
- processor.ctx.size_info.dpr = new_dpr;
- processor.ctx.terminal.dirty = true;
- },
- CursorLeft { .. } => processor.ctx.terminal.reset_url_highlight(),
- _ => (),
- }
- },
- Event::Awakened => {
- processor.ctx.terminal.dirty = true;
- },
- }
- }
-
- /// Process events. When `wait_for_event` is set, this method is guaranteed
- /// to process at least one event.
- pub fn process_events<'a>(
- &mut self,
- term: &'a FairMutex<Term>,
- window: &mut Window,
- ) -> MutexGuard<'a, Term> {
- // Terminal is lazily initialized the first time an event is returned
- // from the blocking WaitEventsIterator. Otherwise, the pty reader would
- // be blocked the entire time we wait for input!
- let mut terminal;
-
- self.pending_events.clear();
-
- {
- // Ditto on lazy initialization for context and processor.
- let context;
- let mut processor: input::Processor<'_, ActionContext<'_, N>>;
-
- let print_events = self.print_events;
-
- let resize_tx = &self.resize_tx;
-
- if self.wait_for_event {
- // A Vec is used here since wait_events can potentially yield
- // multiple events before the interrupt is handled. For example,
- // Resize and Moved events.
- let pending_events = &mut self.pending_events;
- window.wait_events(|e| {
- pending_events.push(e);
- glutin::ControlFlow::Break
- });
- }
-
- terminal = term.lock();
-
- context = ActionContext {
- terminal: &mut terminal,
- notifier: &mut self.notifier,
- mouse: &mut self.mouse,
- size_info: &mut self.size_info,
- received_count: &mut self.received_count,
- suppress_chars: &mut self.suppress_chars,
- modifiers: &mut self.modifiers,
- window_changes: &mut self.window_changes,
- };
-
- processor = input::Processor {
- ctx: context,
- scrolling_config: &self.scrolling_config,
- mouse_config: &self.mouse_config,
- key_bindings: &self.key_bindings[..],
- mouse_bindings: &self.mouse_bindings[..],
- save_to_clipboard: self.save_to_clipboard,
- alt_send_esc: self.alt_send_esc,
- };
-
- let mut window_is_focused = window.is_focused;
-
- // Scope needed to that hide_mouse isn't borrowed after the scope
- // ends.
- {
- let hide_mouse = &mut self.hide_mouse;
- let mut process = |event| {
- if print_events {
- info!("glutin event: {:?}", event);
- }
- Processor::handle_event(
- &mut processor,
- event,
- resize_tx,
- hide_mouse,
- &mut window_is_focused,
- );
- };
-
- for event in self.pending_events.drain(..) {
- process(event);
- }
-
- window.poll_events(process);
- }
-
- if self.hide_mouse_when_typing {
- window.set_mouse_visible(!self.hide_mouse);
- }
-
- window.is_focused = window_is_focused;
- }
-
- if self.window_changes.hide {
- window.hide();
- }
-
- #[cfg(target_os = "macos")]
- {
- if self.window_changes.toggle_simple_fullscreen && !self.is_fullscreen {
- window.set_simple_fullscreen(!self.is_simple_fullscreen);
- self.is_simple_fullscreen = !self.is_simple_fullscreen;
- }
- }
-
- if self.window_changes.toggle_fullscreen && !self.is_simple_fullscreen {
- window.set_fullscreen(!self.is_fullscreen);
- self.is_fullscreen = !self.is_fullscreen;
- }
-
- self.window_changes.clear();
- self.wait_for_event = !terminal.dirty;
-
- terminal
- }
-
- pub fn update_config(&mut self, config: &Config) {
- self.key_bindings = config.key_bindings.to_vec();
- self.mouse_bindings = config.mouse_bindings.to_vec();
- self.mouse_config = config.mouse.to_owned();
- self.save_to_clipboard = config.selection.save_to_clipboard;
- self.alt_send_esc = config.alt_send_esc();
- }
+/// Event Loop for notifying the renderer about terminal events
+pub trait EventListener {
+ fn send_event(&self, event: Event);
}
diff --git a/alacritty_terminal/src/event_loop.rs b/alacritty_terminal/src/event_loop.rs
index 275d752c..ed78d79e 100644
--- a/alacritty_terminal/src/event_loop.rs
+++ b/alacritty_terminal/src/event_loop.rs
@@ -6,20 +6,22 @@ use std::io::{self, ErrorKind, Read, Write};
use std::marker::Send;
use std::sync::Arc;
-use mio::{self, Events, PollOpt, Ready};
-use mio_extras::channel::{self, Receiver, Sender};
-
+use log::error;
#[cfg(not(windows))]
use mio::unix::UnixReady;
+use mio::{self, Events, PollOpt, Ready};
+use mio_extras::channel::{self, Receiver, Sender};
use crate::ansi;
-use crate::display;
-use crate::event;
+use crate::event::{self, Event, EventListener};
use crate::sync::FairMutex;
use crate::term::Term;
use crate::tty;
use crate::util::thread;
+/// Max bytes to read from the PTY
+const MAX_READ: usize = 0x10_000;
+
/// Messages that may be sent to the `EventLoop`
#[derive(Debug)]
pub enum Msg {
@@ -34,13 +36,13 @@ pub enum Msg {
///
/// Handles all the pty I/O and runs the pty parser which updates terminal
/// state.
-pub struct EventLoop<T: tty::EventedPty> {
+pub struct EventLoop<T: tty::EventedPty, U: EventListener> {
poll: mio::Poll,
pty: T,
rx: Receiver<Msg>,
tx: Sender<Msg>,
- terminal: Arc<FairMutex<Term>>,
- display: display::Notifier,
+ terminal: Arc<FairMutex<Term<U>>>,
+ event_proxy: U,
ref_test: bool,
}
@@ -50,26 +52,6 @@ struct Writing {
written: usize,
}
-/// Indicates the result of draining the mio channel
-#[derive(Debug)]
-enum DrainResult {
- /// At least one new item was received
- ReceivedItem,
- /// Nothing was available to receive
- Empty,
- /// A shutdown message was received
- Shutdown,
-}
-
-impl DrainResult {
- pub fn is_shutdown(&self) -> bool {
- match *self {
- DrainResult::Shutdown => true,
- _ => false,
- }
- }
-}
-
/// All of the mutable state needed to run the event loop
///
/// Contains list of items to write, current write state, etc. Anything that
@@ -155,17 +137,18 @@ impl Writing {
}
}
-impl<T> EventLoop<T>
+impl<T, U> EventLoop<T, U>
where
T: tty::EventedPty + Send + 'static,
+ U: EventListener + Send + 'static,
{
/// Create a new event loop
pub fn new(
- terminal: Arc<FairMutex<Term>>,
- display: display::Notifier,
+ terminal: Arc<FairMutex<Term<U>>>,
+ event_proxy: U,
pty: T,
ref_test: bool,
- ) -> EventLoop<T> {
+ ) -> EventLoop<T, U> {
let (tx, rx) = channel::channel();
EventLoop {
poll: mio::Poll::new().expect("create mio Poll"),
@@ -173,7 +156,7 @@ where
tx,
rx,
terminal,
- display,
+ event_proxy,
ref_test,
}
}
@@ -184,33 +167,22 @@ where
// Drain the channel
//
- // Returns a `DrainResult` indicating the result of receiving from the channel
- //
- fn drain_recv_channel(&self, state: &mut State) -> DrainResult {
- let mut received_item = false;
+ // Returns `false` when a shutdown message was received.
+ fn drain_recv_channel(&self, state: &mut State) -> bool {
while let Ok(msg) = self.rx.try_recv() {
- received_item = true;
match msg {
- Msg::Input(input) => {
- state.write_list.push_back(input);
- },
- Msg::Shutdown => {
- return DrainResult::Shutdown;
- },
+ Msg::Input(input) => state.write_list.push_back(input),
+ Msg::Shutdown => return false,
}
}
- if received_item {
- DrainResult::ReceivedItem
- } else {
- DrainResult::Empty
- }
+ true
}
// Returns a `bool` indicating whether or not the event loop should continue running
#[inline]
fn channel_event(&mut self, token: mio::Token, state: &mut State) -> bool {
- if self.drain_recv_channel(state).is_shutdown() {
+ if !self.drain_recv_channel(state) {
return false;
}
@@ -231,13 +203,9 @@ where
where
X: Write,
{
- const MAX_READ: usize = 0x1_0000;
let mut processed = 0;
let mut terminal = None;
- // Flag to keep track if wakeup has already been sent
- let mut send_wakeup = false;
-
loop {
match self.pty.reader().read(&mut buf[..]) {
Ok(0) => break,
@@ -255,14 +223,10 @@ where
// Get reference to terminal. Lock is acquired on initial
// iteration and held until there's no bytes left to parse
// or we've reached MAX_READ.
- let terminal = if terminal.is_none() {
+ if terminal.is_none() {
terminal = Some(self.terminal.lock());
- let terminal = terminal.as_mut().unwrap();
- send_wakeup = !terminal.dirty;
- terminal
- } else {
- terminal.as_mut().unwrap()
- };
+ }
+ let terminal = terminal.as_mut().unwrap();
// Run the parser
for byte in &buf[..got] {
@@ -283,13 +247,8 @@ where
}
}
- // Only request a draw if one hasn't already been requested.
- if let Some(mut terminal) = terminal {
- if send_wakeup {
- self.display.notify();
- terminal.dirty = true;
- }
- }
+ // Queue terminal redraw
+ self.event_proxy.send_event(Event::Wakeup);
Ok(())
}
@@ -326,10 +285,10 @@ where
Ok(())
}
- pub fn spawn(mut self, state: Option<State>) -> thread::JoinHandle<(Self, State)> {
+ pub fn spawn(mut self) -> thread::JoinHandle<(Self, State)> {
thread::spawn_named("pty reader", move || {
- let mut state = state.unwrap_or_else(Default::default);
- let mut buf = [0u8; 0x1000];
+ let mut state = State::default();
+ let mut buf = [0u8; MAX_READ];
let mut tokens = (0..).map(Into::into);
@@ -369,7 +328,7 @@ where
token if token == self.pty.child_event_token() => {
if let Some(tty::ChildEvent::Exited) = self.pty.next_child_event() {
self.terminal.lock().exit();
- self.display.notify();
+ self.event_proxy.send_event(Event::Wakeup);
break 'event_loop;
}
},
diff --git a/alacritty_terminal/src/grid/mod.rs b/alacritty_terminal/src/grid/mod.rs
index 01c17152..5f5b84fe 100644
--- a/alacritty_terminal/src/grid/mod.rs
+++ b/alacritty_terminal/src/grid/mod.rs
@@ -17,6 +17,8 @@
use std::cmp::{max, min, Ordering};
use std::ops::{Deref, Index, IndexMut, Range, RangeFrom, RangeFull, RangeInclusive, RangeTo};
+use serde::{Deserialize, Serialize};
+
use crate::index::{self, Column, IndexRange, Line, Point};
use crate::selection::Selection;
diff --git a/alacritty_terminal/src/grid/row.rs b/alacritty_terminal/src/grid/row.rs
index f82e7eaa..058583f2 100644
--- a/alacritty_terminal/src/grid/row.rs
+++ b/alacritty_terminal/src/grid/row.rs
@@ -19,6 +19,8 @@ use std::ops::{Index, IndexMut};
use std::ops::{Range, RangeFrom, RangeFull, RangeTo, RangeToInclusive};
use std::slice;
+use serde::{Deserialize, Serialize};
+
use crate::grid::GridCell;
use crate::index::Column;
diff --git a/alacritty_terminal/src/grid/storage.rs b/alacritty_terminal/src/grid/storage.rs
index e04d01cd..2004cece 100644
--- a/alacritty_terminal/src/grid/storage.rs
+++ b/alacritty_terminal/src/grid/storage.rs
@@ -14,6 +14,7 @@
use std::ops::{Index, IndexMut};
use std::vec::Drain;
+use serde::{Deserialize, Serialize};
use static_assertions::assert_eq_size;
use super::Row;
diff --git a/alacritty_terminal/src/index.rs b/alacritty_terminal/src/index.rs
index 7d1a8e91..0a100e18 100644
--- a/alacritty_terminal/src/index.rs
+++ b/alacritty_terminal/src/index.rs
@@ -19,6 +19,8 @@ use std::cmp::{Ord, Ordering};
use std::fmt;
use std::ops::{self, Add, AddAssign, Deref, Range, RangeInclusive, Sub, SubAssign};
+use serde::{Deserialize, Serialize};
+
use crate::term::RenderableCell;
/// The side of a cell
@@ -77,8 +79,8 @@ impl From<Point> for Point<usize> {
}
}
-impl From<&RenderableCell> for Point<Line> {
- fn from(cell: &RenderableCell) -> Self {
+impl From<RenderableCell> for Point<Line> {
+ fn from(cell: RenderableCell) -> Self {
Point::new(cell.line, cell.column)
}
}
diff --git a/alacritty_terminal/src/lib.rs b/alacritty_terminal/src/lib.rs
index 0bada535..dc26046d 100644
--- a/alacritty_terminal/src/lib.rs
+++ b/alacritty_terminal/src/lib.rs
@@ -17,27 +17,18 @@
#![cfg_attr(feature = "nightly", feature(core_intrinsics))]
#![cfg_attr(all(test, feature = "bench"), feature(test))]
-#[macro_use]
-extern crate log;
-#[macro_use]
-extern crate serde_derive;
-
#[cfg(target_os = "macos")]
#[macro_use]
extern crate objc;
-#[macro_use]
-pub mod macros;
pub mod ansi;
pub mod clipboard;
pub mod config;
mod cursor;
-pub mod display;
pub mod event;
pub mod event_loop;
pub mod grid;
pub mod index;
-pub mod input;
pub mod locale;
pub mod message_bar;
pub mod meter;
@@ -47,9 +38,8 @@ pub mod selection;
pub mod sync;
pub mod term;
pub mod tty;
-mod url;
+pub mod url;
pub mod util;
-pub mod window;
pub use crate::grid::Grid;
pub use crate::term::Term;
diff --git a/alacritty_terminal/src/macros.rs b/alacritty_terminal/src/macros.rs
deleted file mode 100644
index 519f8b6a..00000000
--- a/alacritty_terminal/src/macros.rs
+++ /dev/null
@@ -1,21 +0,0 @@
-// Copyright 2016 Joe Wilm, The Alacritty Project Contributors
-//
-// Licensed under the Apache License, Version 2.0 (the "License");
-// you may not use this file except in compliance with the License.
-// You may obtain a copy of the License at
-//
-// http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing, software
-// distributed under the License is distributed on an "AS IS" BASIS,
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-// See the License for the specific language governing permissions and
-// limitations under the License.
-
-#[macro_export]
-macro_rules! die {
- ($($arg:tt)*) => {{
- error!($($arg)*);
- ::std::process::exit(1);
- }}
-}
diff --git a/alacritty_terminal/src/message_bar.rs b/alacritty_terminal/src/message_bar.rs
index 8883dcb0..1382684d 100644
--- a/alacritty_terminal/src/message_bar.rs
+++ b/alacritty_terminal/src/message_bar.rs
@@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-use crossbeam_channel::{Receiver, Sender};
+use std::collections::VecDeque;
use crate::term::color::Rgb;
use crate::term::SizeInfo;
@@ -22,21 +22,21 @@ const CLOSE_BUTTON_PADDING: usize = 1;
const MIN_FREE_LINES: usize = 3;
const TRUNCATED_MESSAGE: &str = "[MESSAGE TRUNCATED]";
-/// Message for display in the MessageBuffer
+/// Message for display in the MessageBuffer.
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct Message {
text: String,
color: Rgb,
- topic: Option<String>,
+ target: Option<String>,
}
impl Message {
- /// Create a new message
+ /// Create a new message.
pub fn new(text: String, color: Rgb) -> Message {
- Message { text, color, topic: None }
+ Message { text, color, target: None }
}
- /// Formatted message text lines
+ /// Formatted message text lines.
pub fn text(&self, size_info: &SizeInfo) -> Vec<String> {
let num_cols = size_info.cols().0;
let max_lines = size_info.lines().saturating_sub(MIN_FREE_LINES);
@@ -92,25 +92,25 @@ impl Message {
lines
}
- /// Message color
+ /// Message color.
#[inline]
pub fn color(&self) -> Rgb {
self.color
}
- /// Message topic
+ /// Message target.
#[inline]
- pub fn topic(&self) -> Option<&String> {
- self.topic.as_ref()
+ pub fn target(&self) -> Option<&String> {
+ self.target.as_ref()
}
- /// Update the message topic
+ /// Update the message target.
#[inline]
- pub fn set_topic(&mut self, topic: String) {
- self.topic = Some(topic);
+ pub fn set_target(&mut self, target: String) {
+ self.target = Some(target);
}
- /// Right-pad text to fit a specific number of columns
+ /// Right-pad text to fit a specific number of columns.
#[inline]
fn pad_text(mut text: String, num_cols: usize) -> String {
let padding_len = num_cols.saturating_sub(text.len());
@@ -119,82 +119,56 @@ impl Message {
}
}
-/// Storage for message bar
-#[derive(Debug)]
+/// Storage for message bar.
+#[derive(Debug, Default)]
pub struct MessageBuffer {
- current: Option<Message>,
- messages: Receiver<Message>,
- tx: Sender<Message>,
+ messages: VecDeque<Message>,
}
impl MessageBuffer {
- /// Create new message buffer
+ /// Create new message buffer.
pub fn new() -> MessageBuffer {
- let (tx, messages) = crossbeam_channel::unbounded();
- MessageBuffer { current: None, messages, tx }
+ MessageBuffer { messages: VecDeque::new() }
}
- /// Check if there are any messages queued
+ /// Check if there are any messages queued.
#[inline]
pub fn is_empty(&self) -> bool {
- self.current.is_none()
+ self.messages.is_empty()
}
- /// Current message
+ /// Current message.
#[inline]
- pub fn message(&mut self) -> Option<Message> {
- if let Some(current) = &self.current {
- Some(current.clone())
- } else {
- self.current = self.messages.try_recv().ok();
- self.current.clone()
- }
- }
-
- /// Channel for adding new messages
- #[inline]
- pub fn tx(&self) -> Sender<Message> {
- self.tx.clone()
+ pub fn message(&self) -> Option<&Message> {
+ self.messages.front()
}
- /// Remove the currently visible message
+ /// Remove the currently visible message.
#[inline]
pub fn pop(&mut self) {
+ // Remove the message itself
+ let msg = self.messages.pop_front();
+
// Remove all duplicates
- for msg in self
- .messages
- .try_iter()
- .take(self.messages.len())
- .filter(|m| Some(m) != self.current.as_ref())
- {
- let _ = self.tx.send(msg);
+ if let Some(msg) = msg {
+ self.messages = self.messages.drain(..).filter(|m| m != &msg).collect();
}
-
- // Remove the message itself
- self.current = self.messages.try_recv().ok();
}
- /// Remove all messages with a specific topic
+ /// Remove all messages with a specific target.
#[inline]
- pub fn remove_topic(&mut self, topic: &str) {
- // Filter messages currently pending
- for msg in self
+ pub fn remove_target(&mut self, target: &str) {
+ self.messages = self
.messages
- .try_iter()
- .take(self.messages.len())
- .filter(|m| m.topic().map(String::as_str) != Some(topic))
- {
- let _ = self.tx.send(msg);
- }
-
- // Remove the currently active message
- self.current = self.messages.try_recv().ok();
+ .drain(..)
+ .filter(|m| m.target().map(String::as_str) != Some(target))
+ .collect();
}
-}
-impl Default for MessageBuffer {
- fn default() -> MessageBuffer {
- MessageBuffer::new()
+ /// Add a new message to the queue.
+ #[inline]
+ pub fn push(&mut self, message: Message) {
+ self.messages.push_back(message);
}
}
@@ -207,7 +181,7 @@ mod test {
fn appends_close_button() {
let input = "a";
let mut message_buffer = MessageBuffer::new();
- message_buffer.tx().send(Message::new(input.into(), color::RED)).unwrap();
+ message_buffer.push(Message::new(input.into(), color::RED));
let size = SizeInfo {
width: 7.,
height: 10.,
@@ -227,7 +201,7 @@ mod test {
fn multiline_close_button_first_line() {
let input = "fo\nbar";
let mut message_buffer = MessageBuffer::new();
- message_buffer.tx().send(Message::new(input.into(), color::RED)).unwrap();
+ message_buffer.push(Message::new(input.into(), color::RED));
let size = SizeInfo {
width: 6.,
height: 10.,
@@ -247,7 +221,7 @@ mod test {
fn splits_on_newline() {
let input = "a\nb";
let mut message_buffer = MessageBuffer::new();
- message_buffer.tx().send(Message::new(input.into(), color::RED)).unwrap();
+ message_buffer.push(Message::new(input.into(), color::RED));
let size = SizeInfo {
width: 6.,
height: 10.,
@@ -267,7 +241,7 @@ mod test {
fn splits_on_length() {
let input = "foobar1";
let mut message_buffer = MessageBuffer::new();
- message_buffer.tx().send(Message::new(input.into(), color::RED)).unwrap();
+ message_buffer.push(Message::new(input.into(), color::RED));
let size = SizeInfo {
width: 6.,
height: 10.,
@@ -287,7 +261,7 @@ mod test {
fn empty_with_shortterm() {
let input = "foobar";
let mut message_buffer = MessageBuffer::new();
- message_buffer.tx().send(Message::new(input.into(), color::RED)).unwrap();
+ message_buffer.push(Message::new(input.into(), color::RED));
let size = SizeInfo {
width: 6.,
height: 0.,
@@ -307,7 +281,7 @@ mod test {
fn truncates_long_messages() {
let input = "hahahahahahahahahahaha truncate this because it's too long for the term";
let mut message_buffer = MessageBuffer::new();
- message_buffer.tx().send(Message::new(input.into(), color::RED)).unwrap();
+ message_buffer.push(Message::new(input.into(), color::RED));
let size = SizeInfo {
width: 22.,
height: (MIN_FREE_LINES + 2) as f32,
@@ -330,7 +304,7 @@ mod test {
fn hide_button_when_too_narrow() {
let input = "ha";
let mut message_buffer = MessageBuffer::new();
- message_buffer.tx().send(Message::new(input.into(), color::RED)).unwrap();
+ message_buffer.push(Message::new(input.into(), color::RED));
let size = SizeInfo {
width: 2.,
height: 10.,
@@ -350,7 +324,7 @@ mod test {
fn hide_truncated_when_too_narrow() {
let input = "hahahahahahahahaha";
let mut message_buffer = MessageBuffer::new();
- message_buffer.tx().send(Message::new(input.into(), color::RED)).unwrap();
+ message_buffer.push(Message::new(input.into(), color::RED));
let size = SizeInfo {
width: 2.,
height: (MIN_FREE_LINES + 2) as f32,
@@ -370,7 +344,7 @@ mod test {
fn add_newline_for_button() {
let input = "test";
let mut message_buffer = MessageBuffer::new();
- message_buffer.tx().send(Message::new(input.into(), color::RED)).unwrap();
+ message_buffer.push(Message::new(input.into(), color::RED));
let size = SizeInfo {
width: 5.,
height: 10.,
@@ -387,17 +361,17 @@ mod test {
}
#[test]
- fn remove_topic() {
+ fn remove_target() {
let mut message_buffer = MessageBuffer::new();
for i in 0..10 {
let mut msg = Message::new(i.to_string(), color::RED);
if i % 2 == 0 && i < 5 {
- msg.set_topic("topic".into());
+ msg.set_target("target".into());
}
- message_buffer.tx().send(msg).unwrap();
+ message_buffer.push(msg);
}
- message_buffer.remove_topic("topic");
+ message_buffer.remove_target("target");
// Count number of messages
let mut num_messages = 0;
@@ -413,22 +387,22 @@ mod test {
fn pop() {
let mut message_buffer = MessageBuffer::new();
let one = Message::new(String::from("one"), color::RED);
- message_buffer.tx().send(one.clone()).unwrap();
+ message_buffer.push(one.clone());
let two = Message::new(String::from("two"), color::YELLOW);
- message_buffer.tx().send(two.clone()).unwrap();
+ message_buffer.push(two.clone());
- assert_eq!(message_buffer.message(), Some(one));
+ assert_eq!(message_buffer.message(), Some(&one));
message_buffer.pop();
- assert_eq!(message_buffer.message(), Some(two));
+ assert_eq!(message_buffer.message(), Some(&two));
}
#[test]
fn wrap_on_words() {
let input = "a\nbc defg";
let mut message_buffer = MessageBuffer::new();
- message_buffer.tx().send(Message::new(input.into(), color::RED)).unwrap();
+ message_buffer.push(Message::new(input.into(), color::RED));
let size = SizeInfo {
width: 5.,
height: 10.,
@@ -453,10 +427,10 @@ mod test {
let mut message_buffer = MessageBuffer::new();
for _ in 0..10 {
let msg = Message::new(String::from("test"), color::RED);
- message_buffer.tx().send(msg).unwrap();
+ message_buffer.push(msg);
}
- message_buffer.tx().send(Message::new(String::from("other"), color::RED)).unwrap();
- message_buffer.tx().send(Message::new(String::from("test"), color::YELLOW)).unwrap();
+ message_buffer.push(Message::new(String::from("other"), color::RED));
+ message_buffer.push(Message::new(String::from("test"), color::YELLOW));
let _ = message_buffer.message();
message_buffer.pop();
diff --git a/alacritty_terminal/src/meter.rs b/alacritty_terminal/src/meter.rs
index 19d7fe70..686dd859 100644
--- a/alacritty_terminal/src/meter.rs
+++ b/alacritty_terminal/src/meter.rs
@@ -30,6 +30,7 @@
//! // Get the moving average. The meter tracks a fixed number of samples, and
//! // the average won't mean much until it's filled up at least once.
//! println!("Average time: {}", meter.average());
+//! ```
use std::time::{Duration, Instant};
diff --git a/alacritty_terminal/src/renderer/mod.rs b/alacritty_terminal/src/renderer/mod.rs
index 4aae8536..51c0d0f0 100644
--- a/alacritty_terminal/src/renderer/mod.rs
+++ b/alacritty_terminal/src/renderer/mod.rs
@@ -23,10 +23,10 @@ use std::time::Duration;
use fnv::FnvHasher;
use font::{self, FontDesc, FontKey, GlyphKey, Rasterize, RasterizedGlyph, Rasterizer};
-use glutin::dpi::PhysicalSize;
+use log::{error, info};
use notify::{watcher, DebouncedEvent, RecursiveMode, Watcher};
-use crate::config::{self, Config, Delta};
+use crate::config::{self, Config, Delta, Font, StartupMode};
use crate::cursor::{get_cursor_glyph, CursorKey};
use crate::gl;
use crate::gl::types::*;
@@ -34,7 +34,9 @@ use crate::index::{Column, Line};
use crate::renderer::rects::RenderRect;
use crate::term::cell::{self, Flags};
use crate::term::color::Rgb;
+use crate::term::SizeInfo;
use crate::term::{self, RenderableCell, RenderableCellContent};
+use crate::util;
pub mod rects;
@@ -284,12 +286,6 @@ impl GlyphCache {
FontDesc::new(desc.family.clone(), style)
}
- pub fn font_metrics(&self) -> font::Metrics {
- self.rasterizer
- .metrics(self.font_key, self.font_size)
- .expect("metrics load since font is loaded at glyph cache creation")
- }
-
pub fn get<'a, L>(&'a mut self, glyph_key: GlyphKey, loader: &mut L) -> &'a Glyph
where
L: LoadGlyph,
@@ -311,8 +307,7 @@ impl GlyphCache {
pub fn update_font_size<L: LoadGlyph>(
&mut self,
- font: &config::Font,
- size: font::Size,
+ font: config::Font,
dpr: f64,
loader: &mut L,
) -> Result<(), font::Error> {
@@ -325,12 +320,11 @@ impl GlyphCache {
self.rasterizer.update_dpr(dpr as f32);
// Recompute font keys
- let font = font.to_owned().with_size(size);
let (regular, bold, italic, bold_italic) =
Self::compute_font_keys(&font, &mut self.rasterizer)?;
self.rasterizer.get_glyph(GlyphKey { font_key: regular, c: 'm', size: font.size })?;
- let metrics = self.rasterizer.metrics(regular, size)?;
+ let metrics = self.rasterizer.metrics(regular, font.size)?;
info!("Font size changed to {:?} with DPR of {}", font.size, dpr);
@@ -349,13 +343,15 @@ impl GlyphCache {
Ok(())
}
- // Calculate font metrics without access to a glyph cache
- //
- // This should only be used *before* OpenGL is initialized and the glyph cache can be filled.
- pub fn static_metrics(config: &Config, dpr: f32) -> Result<font::Metrics, font::Error> {
- let font = config.font.clone();
+ pub fn font_metrics(&self) -> font::Metrics {
+ self.rasterizer
+ .metrics(self.font_key, self.font_size)
+ .expect("metrics load since font is loaded at glyph cache creation")
+ }
- let mut rasterizer = font::Rasterizer::new(dpr, config.font.use_thin_strokes())?;
+ // Calculate font metrics without access to a glyph cache
+ pub fn static_metrics(font: Font, dpr: f64) -> Result<font::Metrics, font::Error> {
+ let mut rasterizer = font::Rasterizer::new(dpr as f32, font.use_thin_strokes())?;
let regular_desc =
GlyphCache::make_desc(&font.normal(), font::Slant::Normal, font::Weight::Normal);
let regular = rasterizer.load_font(&regular_desc, font.size)?;
@@ -363,6 +359,34 @@ impl GlyphCache {
rasterizer.metrics(regular, font.size)
}
+
+ pub fn calculate_dimensions<C>(
+ config: &Config<C>,
+ dpr: f64,
+ cell_width: f32,
+ cell_height: f32,
+ ) -> Option<(f64, f64)> {
+ let dimensions = config.window.dimensions;
+
+ if dimensions.columns_u32() == 0
+ || dimensions.lines_u32() == 0
+ || config.window.startup_mode() != StartupMode::Windowed
+ {
+ return None;
+ }
+
+ let padding_x = f64::from(config.window.padding.x) * dpr;
+ let padding_y = f64::from(config.window.padding.y) * dpr;
+
+ // Calculate new size based on cols/lines specified in config
+ let grid_width = cell_width as u32 * dimensions.columns_u32();
+ let grid_height = cell_height as u32 * dimensions.lines_u32();
+
+ let width = (f64::from(grid_width) + 2. * padding_x).floor();
+ let height = (f64::from(grid_height) + 2. * padding_y).floor();
+
+ Some((width, height))
+ }
}
#[derive(Debug)]
@@ -411,13 +435,13 @@ pub struct QuadRenderer {
}
#[derive(Debug)]
-pub struct RenderApi<'a> {
+pub struct RenderApi<'a, C> {
active_tex: &'a mut GLuint,
batch: &'a mut Batch,
atlas: &'a mut Vec<Atlas>,
current_atlas: &'a mut usize,
program: &'a mut TextShaderProgram,
- config: &'a Config,
+ config: &'a Config<C>,
}
#[derive(Debug)]
@@ -445,7 +469,7 @@ impl Batch {
Batch { tex: 0, instances: Vec::with_capacity(BATCH_MAX) }
}
- pub fn add_item(&mut self, cell: &RenderableCell, glyph: &Glyph) {
+ pub fn add_item(&mut self, cell: RenderableCell, glyph: &Glyph) {
if self.is_empty() {
self.tex = glyph.tex_id;
}
@@ -639,7 +663,7 @@ impl QuadRenderer {
let (msg_tx, msg_rx) = mpsc::channel();
if cfg!(feature = "live-shader-reload") {
- ::std::thread::spawn(move || {
+ util::thread::spawn_named("live shader reload", move || {
let (tx, rx) = ::std::sync::mpsc::channel();
// The Duration argument is a debouncing period.
let mut watcher =
@@ -691,8 +715,8 @@ impl QuadRenderer {
// Draw all rectangles simultaneously to prevent excessive program swaps
pub fn draw_rects(
&mut self,
- config: &Config,
props: &term::SizeInfo,
+ visual_bell_color: Rgb,
visual_bell_intensity: f64,
cell_line_rects: Vec<RenderRect>,
) {
@@ -724,8 +748,7 @@ impl QuadRenderer {
}
// Draw visual bell
- let color = config.visual_bell.color;
- let rect = RenderRect::new(0., 0., props.width, props.height, color);
+ let rect = RenderRect::new(0., 0., props.width, props.height, visual_bell_color);
self.render_rect(&rect, visual_bell_intensity as f32, props);
// Draw underlines and strikeouts
@@ -753,9 +776,9 @@ impl QuadRenderer {
}
}
- pub fn with_api<F, T>(&mut self, config: &Config, props: &term::SizeInfo, func: F) -> T
+ pub fn with_api<F, T, C>(&mut self, config: &Config<C>, props: &term::SizeInfo, func: F) -> T
where
- F: FnOnce(RenderApi<'_>) -> T,
+ F: FnOnce(RenderApi<'_, C>) -> T,
{
// Flush message queue
if let Ok(Msg::ShaderReload) = self.rx.try_recv() {
@@ -838,25 +861,19 @@ impl QuadRenderer {
self.rect_program = rect_program;
}
- pub fn resize(&mut self, size: PhysicalSize, padding_x: f32, padding_y: f32) {
- let (width, height): (u32, u32) = size.into();
-
+ pub fn resize(&mut self, size: &SizeInfo) {
// viewport
unsafe {
- let width = width as i32;
- let height = height as i32;
- let padding_x = padding_x as i32;
- let padding_y = padding_y as i32;
- gl::Viewport(padding_x, padding_y, width - 2 * padding_x, height - 2 * padding_y);
+ gl::Viewport(
+ size.padding_x as i32,
+ size.padding_y as i32,
+ size.width as i32 - 2 * size.padding_x as i32,
+ size.height as i32 - 2 * size.padding_y as i32,
+ );
// update projection
gl::UseProgram(self.program.id);
- self.program.update_projection(
- width as f32,
- height as f32,
- padding_x as f32,
- padding_y as f32,
- );
+ self.program.update_projection(size.width, size.height, size.padding_x, size.padding_y);
gl::UseProgram(0);
}
}
@@ -899,10 +916,10 @@ impl QuadRenderer {
}
}
-impl<'a> RenderApi<'a> {
+impl<'a, C> RenderApi<'a, C> {
pub fn clear(&self, color: Rgb) {
- let alpha = self.config.background_opacity();
unsafe {
+ let alpha = self.config.background_opacity();
gl::ClearColor(
(f32::from(color.r) / 255.0).min(1.0) * alpha,
(f32::from(color.g) / 255.0).min(1.0) * alpha,
@@ -989,7 +1006,7 @@ impl<'a> RenderApi<'a> {
}
#[inline]
- fn add_render_item(&mut self, cell: &RenderableCell, glyph: &Glyph) {
+ fn add_render_item(&mut self, cell: RenderableCell, glyph: &Glyph) {
// Flush batch if tex changing
if !self.batch.is_empty() && self.batch.tex != glyph.tex_id {
self.render_batch();
@@ -1009,18 +1026,15 @@ impl<'a> RenderApi<'a> {
// Raw cell pixel buffers like cursors don't need to go through font lookup
let metrics = glyph_cache.metrics;
let glyph = glyph_cache.cursor_cache.entry(cursor_key).or_insert_with(|| {
- let offset_x = self.config.font.offset.x;
- let offset_y = self.config.font.offset.y;
-
self.load_glyph(&get_cursor_glyph(
cursor_key.style,
metrics,
- offset_x,
- offset_y,
+ self.config.font.offset.x,
+ self.config.font.offset.y,
cursor_key.is_wide,
))
});
- self.add_render_item(&cell, &glyph);
+ self.add_render_item(cell, &glyph);
return;
},
RenderableCellContent::Chars(chars) => chars,
@@ -1050,7 +1064,7 @@ impl<'a> RenderApi<'a> {
// Add cell to batch
let glyph = glyph_cache.get(glyph_key, self);
- self.add_render_item(&cell, glyph);
+ self.add_render_item(cell, glyph);
// Render zero-width characters
for c in (&chars[1..]).iter().filter(|c| **c != ' ') {
@@ -1064,7 +1078,7 @@ impl<'a> RenderApi<'a> {
// anchor has been moved to the right by one cell.
glyph.left += glyph_cache.metrics.average_advance as f32;
- self.add_render_item(&cell, &glyph);
+ self.add_render_item(cell, &glyph);
}
}
}
@@ -1124,7 +1138,7 @@ impl<'a> LoadGlyph for LoaderApi<'a> {
}
}
-impl<'a> LoadGlyph for RenderApi<'a> {
+impl<'a, C> LoadGlyph for RenderApi<'a, C> {
fn load_glyph(&mut self, rasterized: &RasterizedGlyph) -> Glyph {
load_glyph(self.active_tex, self.atlas, self.current_atlas, rasterized)
}
@@ -1134,7 +1148,7 @@ impl<'a> LoadGlyph for RenderApi<'a> {
}
}
-impl<'a> Drop for RenderApi<'a> {
+impl<'a, C> Drop for RenderApi<'a, C> {
fn drop(&mut self) {
if !self.batch.is_empty() {
self.render_batch();
diff --git a/alacritty_terminal/src/renderer/rects.rs b/alacritty_terminal/src/renderer/rects.rs
index 72139e3d..dd72f673 100644
--- a/alacritty_terminal/src/renderer/rects.rs
+++ b/alacritty_terminal/src/renderer/rects.rs
@@ -91,7 +91,7 @@ impl RenderLines {
}
/// Update the stored lines with the next cell info.
- pub fn update(&mut self, cell: &RenderableCell) {
+ pub fn update(&mut self, cell: RenderableCell) {
for flag in &[Flags::UNDERLINE, Flags::STRIKEOUT] {
if !cell.flags.contains(*flag) {
continue;
diff --git a/alacritty_terminal/src/selection.rs b/alacritty_terminal/src/selection.rs
index ffe35e08..29934e5a 100644
--- a/alacritty_terminal/src/selection.rs
+++ b/alacritty_terminal/src/selection.rs
@@ -39,6 +39,7 @@ use crate::term::{Search, Term};
/// [`simple`]: enum.Selection.html#method.simple
/// [`semantic`]: enum.Selection.html#method.semantic
/// [`lines`]: enum.Selection.html#method.lines
+/// [`update`]: enum.Selection.html#method.update
#[derive(Debug, Clone, PartialEq)]
pub enum Selection {
Simple {
@@ -164,7 +165,7 @@ impl Selection {
}
}
- pub fn to_span(&self, term: &Term) -> Option<Span> {
+ pub fn to_span<T>(&self, term: &Term<T>) -> Option<Span> {
// Get both sides of the selection
let (mut start, mut end) = match *self {
Selection::Simple { ref region } | Selection::Block { ref region } => {
@@ -405,13 +406,19 @@ mod test {
use super::{Selection, Span};
use crate::clipboard::Clipboard;
+ use crate::config::MockConfig;
+ use crate::event::{Event, EventListener};
use crate::grid::Grid;
use crate::index::{Column, Line, Point, Side};
- use crate::message_bar::MessageBuffer;
use crate::term::cell::{Cell, Flags};
use crate::term::{SizeInfo, Term};
- fn term(width: usize, height: usize) -> Term {
+ struct Mock;
+ impl EventListener for Mock {
+ fn send_event(&self, _event: Event) {}
+ }
+
+ fn term(width: usize, height: usize) -> Term<Mock> {
let size = SizeInfo {
width: width as f32,
height: height as f32,
@@ -421,7 +428,7 @@ mod test {
padding_y: 0.0,
dpr: 1.0,
};
- Term::new(&Default::default(), size, MessageBuffer::new(), Clipboard::new_nop())
+ Term::new(&MockConfig::default(), &size, Clipboard::new_nop(), Mock)
}
/// Test case of single cell selection
diff --git a/alacritty_terminal/src/term/cell.rs b/alacritty_terminal/src/term/cell.rs
index 7a759777..234805f9 100644
--- a/alacritty_terminal/src/term/cell.rs
+++ b/alacritty_terminal/src/term/cell.rs
@@ -13,6 +13,8 @@
// limitations under the License.
use bitflags::bitflags;
+use serde::{Deserialize, Serialize};
+
use crate::ansi::{Color, NamedColor};
use crate::grid::{self, GridCell};
use crate::index::Column;
diff --git a/alacritty_terminal/src/term/color.rs b/alacritty_terminal/src/term/color.rs
index f2db335a..e9f0a26d 100644
--- a/alacritty_terminal/src/term/color.rs
+++ b/alacritty_terminal/src/term/color.rs
@@ -2,8 +2,9 @@ use std::fmt;
use std::ops::{Index, IndexMut, Mul};
use std::str::FromStr;
+use log::{error, trace};
use serde::de::Visitor;
-use serde::{Deserialize, Deserializer};
+use serde::{Deserialize, Deserializer, Serialize};
use crate::ansi;
use crate::config::Colors;
diff --git a/alacritty_terminal/src/term/mod.rs b/alacritty_terminal/src/term/mod.rs
index 58d06318..4e51d734 100644
--- a/alacritty_terminal/src/term/mod.rs
+++ b/alacritty_terminal/src/term/mod.rs
@@ -18,9 +18,9 @@ use std::ops::{Index, IndexMut, Range, RangeInclusive};
use std::time::{Duration, Instant};
use std::{io, mem, ptr};
-use font::{self, Size};
-use glutin::MouseCursor;
+use log::{debug, trace};
use rfind_url::{Parser, ParserState};
+use serde::{Deserialize, Serialize};
use unicode_width::UnicodeWidthChar;
use crate::ansi::{
@@ -29,19 +29,17 @@ use crate::ansi::{
use crate::clipboard::{Clipboard, ClipboardType};
use crate::config::{Config, VisualBellAnimation};
use crate::cursor::CursorKey;
+use crate::event::{Event, EventListener};
use crate::grid::{
BidirectionalIterator, DisplayIter, Grid, GridCell, IndexRegion, Indexed, Scroll,
};
use crate::index::{self, Column, Contains, IndexRange, Line, Linear, Point};
-use crate::input::FONT_SIZE_STEP;
-use crate::message_bar::MessageBuffer;
use crate::selection::{self, Selection, SelectionRange, Span};
use crate::term::cell::{Cell, Flags, LineLength};
use crate::term::color::Rgb;
-use crate::url::Url;
-
#[cfg(windows)]
use crate::tty;
+use crate::url::Url;
pub mod cell;
pub mod color;
@@ -62,7 +60,7 @@ pub trait Search {
fn bracket_search(&self, _: Point<usize>) -> Option<Point<usize>>;
}
-impl Search for Term {
+impl<T> Search for Term<T> {
fn semantic_search_left(&self, mut point: Point<usize>) -> Point<usize> {
// Limit the starting point to the last line in the history
point.line = min(point.line, self.grid.len() - 1);
@@ -151,7 +149,7 @@ impl Search for Term {
}
}
-impl selection::Dimensions for Term {
+impl<T> selection::Dimensions for Term<T> {
fn dimensions(&self) -> Point {
let line = if self.mode.contains(TermMode::ALT_SCREEN) {
self.grid.num_lines()
@@ -170,30 +168,30 @@ impl selection::Dimensions for Term {
///
/// This manages the cursor during a render. The cursor location is inverted to
/// draw it, and reverted after drawing to maintain state.
-pub struct RenderableCellsIter<'a> {
+pub struct RenderableCellsIter<'a, C> {
inner: DisplayIter<'a, Cell>,
grid: &'a Grid<Cell>,
cursor: &'a Point,
cursor_offset: usize,
cursor_key: Option<CursorKey>,
cursor_style: CursorStyle,
- config: &'a Config,
+ config: &'a Config<C>,
colors: &'a color::List,
selection: Option<SelectionRange>,
url_highlight: &'a Option<RangeInclusive<index::Linear>>,
}
-impl<'a> RenderableCellsIter<'a> {
+impl<'a, C> RenderableCellsIter<'a, C> {
/// Create the renderable cells iterator
///
/// The cursor and terminal mode are required for properly displaying the
/// cursor.
- fn new<'b>(
- term: &'b Term,
- config: &'b Config,
+ fn new<'b, T>(
+ term: &'b Term<T>,
+ config: &'b Config<C>,
selection: Option<Span>,
mut cursor_style: CursorStyle,
- ) -> RenderableCellsIter<'b> {
+ ) -> RenderableCellsIter<'b, C> {
let grid = &term.grid;
let cursor_offset = grid.line_to_offset(term.cursor.point.line);
@@ -250,13 +248,13 @@ impl<'a> RenderableCellsIter<'a> {
}
}
-#[derive(Clone, Debug)]
+#[derive(Copy, Clone, Debug)]
pub enum RenderableCellContent {
Chars([char; cell::MAX_ZEROWIDTH_CHARS + 1]),
Cursor(CursorKey),
}
-#[derive(Clone, Debug)]
+#[derive(Copy, Clone, Debug)]
pub struct RenderableCell {
/// A _Display_ line (not necessarily an _Active_ line)
pub line: Line,
@@ -269,7 +267,12 @@ pub struct RenderableCell {
}
impl RenderableCell {
- fn new(config: &Config, colors: &color::List, cell: Indexed<Cell>, selected: bool) -> Self {
+ fn new<C>(
+ config: &Config<C>,
+ colors: &color::List,
+ cell: Indexed<Cell>,
+ selected: bool,
+ ) -> Self {
// Lookup RGB values
let mut fg_rgb = Self::compute_fg_rgb(config, colors, cell.fg, cell.flags);
let mut bg_rgb = Self::compute_bg_rgb(colors, cell.bg);
@@ -309,7 +312,12 @@ impl RenderableCell {
}
}
- fn compute_fg_rgb(config: &Config, colors: &color::List, fg: Color, flags: cell::Flags) -> Rgb {
+ fn compute_fg_rgb<C>(
+ config: &Config<C>,
+ colors: &color::List,
+ fg: Color,
+ flags: cell::Flags,
+ ) -> Rgb {
match fg {
Color::Spec(rgb) => rgb,
Color::Named(ansi) => {
@@ -365,7 +373,7 @@ impl RenderableCell {
}
}
-impl<'a> Iterator for RenderableCellsIter<'a> {
+impl<'a, C> Iterator for RenderableCellsIter<'a, C> {
type Item = RenderableCell;
/// Gets the next renderable cell
@@ -573,7 +581,7 @@ fn cubic_bezier(p0: f64, p1: f64, p2: f64, p3: f64, x: f64) -> f64 {
}
impl VisualBell {
- pub fn new(config: &Config) -> VisualBell {
+ pub fn new<C>(config: &Config<C>) -> VisualBell {
let visual_bell_config = &config.visual_bell;
VisualBell {
animation: visual_bell_config.animation,
@@ -668,14 +676,14 @@ impl VisualBell {
}
}
- pub fn update_config(&mut self, config: &Config) {
+ pub fn update_config<C>(&mut self, config: &Config<C>) {
let visual_bell_config = &config.visual_bell;
self.animation = visual_bell_config.animation;
self.duration = visual_bell_config.duration();
}
}
-pub struct Term {
+pub struct Term<T> {
/// The grid
grid: Grid<Cell>,
@@ -686,14 +694,6 @@ pub struct Term {
/// arrays. Without it we would have to sanitize cursor.col every time we used it.
input_needs_wrap: bool,
- /// Got a request to set title; it's buffered here until next draw.
- ///
- /// Would be nice to avoid the allocation...
- next_title: Option<String>,
-
- /// Got a request to set the mouse cursor; it's buffered here until the next draw
- next_mouse_cursor: Option<MouseCursor>,
-
/// Alternate grid
alt_grid: Grid<Cell>,
@@ -716,17 +716,9 @@ pub struct Term {
/// Scroll region
scroll_region: Range<Line>,
- /// Font size
- pub font_size: Size,
- original_font_size: Size,
-
- /// Size
- size_info: SizeInfo,
-
pub dirty: bool,
pub visual_bell: VisualBell,
- pub next_is_urgent: Option<bool>,
/// Saved cursor from main grid
cursor_save: Cursor,
@@ -760,18 +752,18 @@ pub struct Term {
/// Automatically scroll to bottom when new lines are added
auto_scroll: bool,
- /// Buffer to store messages for the message bar
- message_buffer: MessageBuffer,
-
- /// Hint that Alacritty should be closed
- should_exit: bool,
-
/// Clipboard access coupled to the active window
clipboard: Clipboard,
+
+ /// Proxy for sending events to the event loop
+ event_proxy: T,
+
+ /// Terminal focus
+ pub is_focused: bool,
}
/// Terminal size info
-#[derive(Debug, Copy, Clone, Serialize, Deserialize)]
+#[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq)]
pub struct SizeInfo {
/// Terminal window width
pub width: f32,
@@ -829,7 +821,7 @@ impl SizeInfo {
}
}
-impl Term {
+impl<T> Term<T> {
pub fn selection(&self) -> &Option<Selection> {
&self.grid.selection
}
@@ -839,29 +831,22 @@ impl Term {
}
#[inline]
- pub fn get_next_title(&mut self) -> Option<String> {
- self.next_title.take()
- }
-
- #[inline]
- pub fn scroll_display(&mut self, scroll: Scroll) {
- self.set_mouse_cursor(MouseCursor::Text);
+ pub fn scroll_display(&mut self, scroll: Scroll)
+ where
+ T: EventListener,
+ {
+ self.event_proxy.send_event(Event::MouseCursorDirty);
self.grid.scroll_display(scroll);
self.reset_url_highlight();
self.dirty = true;
}
- #[inline]
- pub fn get_next_mouse_cursor(&mut self) -> Option<MouseCursor> {
- self.next_mouse_cursor.take()
- }
-
- pub fn new(
- config: &Config,
- size: SizeInfo,
- message_buffer: MessageBuffer,
+ pub fn new<C>(
+ config: &Config<C>,
+ size: &SizeInfo,
clipboard: Clipboard,
- ) -> Term {
+ event_proxy: T,
+ ) -> Term<T> {
let num_cols = size.cols();
let num_lines = size.lines();
@@ -877,17 +862,12 @@ impl Term {
let colors = color::List::from(&config.colors);
Term {
- next_title: None,
- next_mouse_cursor: None,
dirty: false,
visual_bell: VisualBell::new(config),
- next_is_urgent: None,
input_needs_wrap: false,
grid,
alt_grid: alt,
alt: false,
- font_size: config.font.size,
- original_font_size: config.font.size,
active_charset: Default::default(),
cursor: Default::default(),
cursor_save: Default::default(),
@@ -895,7 +875,6 @@ impl Term {
tabs,
mode: Default::default(),
scroll_region,
- size_info: size,
colors,
color_modified: [false; color::COUNT],
original_colors: colors,
@@ -905,25 +884,13 @@ impl Term {
dynamic_title: config.dynamic_title(),
tabspaces,
auto_scroll: config.scrolling.auto_scroll,
- message_buffer,
- should_exit: false,
clipboard,
+ event_proxy,
+ is_focused: true,
}
}
- pub fn change_font_size(&mut self, delta: f32) {
- // Saturating addition with minimum font size FONT_SIZE_STEP
- let new_size = self.font_size + Size::new(delta);
- self.font_size = max(new_size, Size::new(FONT_SIZE_STEP));
- self.dirty = true;
- }
-
- pub fn reset_font_size(&mut self) {
- self.font_size = self.original_font_size;
- self.dirty = true;
- }
-
- pub fn update_config(&mut self, config: &Config) {
+ pub fn update_config<C>(&mut self, config: &Config<C>) {
self.semantic_escape_chars = config.selection.semantic_escape_chars().to_owned();
self.original_colors.fill_named(&config.colors);
self.original_colors.fill_cube(&config.colors);
@@ -938,16 +905,6 @@ impl Term {
self.dynamic_title = config.dynamic_title();
self.auto_scroll = config.scrolling.auto_scroll;
self.grid.update_history(config.scrolling.history() as usize, &self.cursor.template);
-
- if self.original_font_size == self.font_size {
- self.font_size = config.font.size;
- }
- self.original_font_size = config.font.size;
- }
-
- #[inline]
- pub fn needs_draw(&self) -> bool {
- self.dirty
}
pub fn selection_to_string(&self) -> Option<String> {
@@ -1072,21 +1029,6 @@ impl Term {
self.grid.buffer_to_visible(point)
}
- /// Convert the given pixel values to a grid coordinate
- ///
- /// The mouse coordinates are expected to be relative to the top left. The
- /// line and column returned are also relative to the top left.
- ///
- /// Returns None if the coordinates are outside the window,
- /// padding pixels are considered inside the window
- pub fn pixels_to_coords(&self, x: usize, y: usize) -> Option<Point> {
- if self.size_info.contains_point(x, y, true) {
- Some(self.size_info.pixels_to_coords(x, y))
- } else {
- None
- }
- }
-
/// Access to the raw grid data structure
///
/// This is a bit of a hack; when the window is closed, the event processor
@@ -1106,14 +1048,10 @@ impl Term {
/// A renderable cell is any cell which has content other than the default
/// background color. Cells with an alternate background color are
/// considered renderable as are cells with any text content.
- pub fn renderable_cells<'b>(
- &'b self,
- config: &'b Config,
- window_focused: bool,
- ) -> RenderableCellsIter<'_> {
+ pub fn renderable_cells<'b, C>(&'b self, config: &'b Config<C>) -> RenderableCellsIter<'_, C> {
let selection = self.grid.selection.as_ref().and_then(|s| s.to_span(self));
- let cursor = if window_focused || !config.cursor.unfocused_hollow() {
+ let cursor = if self.is_focused || !config.cursor.unfocused_hollow() {
self.cursor_style.unwrap_or(self.default_cursor_style)
} else {
CursorStyle::HollowBlock
@@ -1124,11 +1062,9 @@ impl Term {
/// Resize terminal to new dimensions
pub fn resize(&mut self, size: &SizeInfo) {
- debug!("Resizing terminal");
-
// Bounds check; lots of math assumes width and height are > 0
- if size.width as usize <= 2 * self.size_info.padding_x as usize
- || size.height as usize <= 2 * self.size_info.padding_y as usize
+ if size.width as usize <= 2 * size.padding_x as usize
+ || size.height as usize <= 2 * size.padding_y as usize
{
return;
}
@@ -1138,12 +1074,6 @@ impl Term {
let mut num_cols = size.cols();
let mut num_lines = size.lines();
- if let Some(message) = self.message_buffer.message() {
- num_lines -= message.text(size).len();
- }
-
- self.size_info = *size;
-
if old_cols == num_cols && old_lines == num_lines {
debug!("Term::resize dimensions unchanged");
return;
@@ -1211,11 +1141,6 @@ impl Term {
}
#[inline]
- pub fn size_info(&self) -> &SizeInfo {
- &self.size_info
- }
-
- #[inline]
pub fn mode(&self) -> &TermMode {
&self.mode
}
@@ -1266,7 +1191,10 @@ impl Term {
self.grid.scroll_up(&(origin..self.scroll_region.end), lines, &template);
}
- fn deccolm(&mut self) {
+ fn deccolm(&mut self)
+ where
+ T: EventListener,
+ {
// Setting 132 column font makes no sense, but run the other side effects
// Clear scrolling region
self.set_scrolling_region(1, self.grid.num_lines().0);
@@ -1282,23 +1210,11 @@ impl Term {
}
#[inline]
- pub fn message_buffer_mut(&mut self) -> &mut MessageBuffer {
- &mut self.message_buffer
- }
-
- #[inline]
- pub fn message_buffer(&self) -> &MessageBuffer {
- &self.message_buffer
- }
-
- #[inline]
- pub fn exit(&mut self) {
- self.should_exit = true;
- }
-
- #[inline]
- pub fn should_exit(&self) -> bool {
- self.should_exit
+ pub fn exit(&mut self)
+ where
+ T: EventListener,
+ {
+ self.event_proxy.send_event(Event::Exit);
}
#[inline]
@@ -1389,7 +1305,7 @@ impl Term {
}
}
-impl TermInfo for Term {
+impl<T> TermInfo for Term<T> {
#[inline]
fn lines(&self) -> Line {
self.grid.num_lines()
@@ -1401,33 +1317,33 @@ impl TermInfo for Term {
}
}
-impl ansi::Handler for Term {
- /// Set the window title
+impl<T: EventListener> ansi::Handler for Term<T> {
#[inline]
+ #[cfg(not(windows))]
fn set_title(&mut self, title: &str) {
if self.dynamic_title {
- self.next_title = Some(title.to_owned());
-
- #[cfg(windows)]
- {
- // cmd.exe in winpty: winpty incorrectly sets the title to ' ' instead of
- // 'Alacritty' - thus we have to substitute this back to get equivalent
- // behaviour as conpty.
- //
- // The starts_with check is necessary because other shells e.g. bash set a
- // different title and don't need Alacritty prepended.
- if !tty::is_conpty() && title.starts_with(' ') {
- self.next_title = Some(format!("Alacritty {}", title.trim()));
- }
- }
+ self.event_proxy.send_event(Event::Title(title.to_owned()));
}
}
- /// Set the mouse cursor
#[inline]
- fn set_mouse_cursor(&mut self, cursor: MouseCursor) {
- self.next_mouse_cursor = Some(cursor);
- self.dirty = true;
+ #[cfg(windows)]
+ fn set_title(&mut self, title: &str) {
+ if self.dynamic_title {
+ // cmd.exe in winpty: winpty incorrectly sets the title to ' ' instead of
+ // 'Alacritty' - thus we have to substitute this back to get equivalent
+ // behaviour as conpty.
+ //
+ // The starts_with check is necessary because other shells e.g. bash set a
+ // different title and don't need Alacritty prepended.
+ let title = if !tty::is_conpty() && title.starts_with(' ') {
+ format!("Alacritty {}", title.trim())
+ } else {
+ title.to_owned()
+ };
+
+ self.event_proxy.send_event(Event::Title(title));
+ }
}
/// A character to be displayed
@@ -1554,11 +1470,11 @@ impl ansi::Handler for Term {
fn insert_blank(&mut self, count: Column) {
// Ensure inserting within terminal bounds
- let count = min(count, self.size_info.cols() - self.cursor.point.col);
+ let count = min(count, self.grid.num_cols() - self.cursor.point.col);
let source = self.cursor.point.col;
let destination = self.cursor.point.col + count;
- let num_cells = (self.size_info.cols() - destination).0;
+ let num_cells = (self.grid.num_cols() - destination).0;
let line = &mut self.grid[self.cursor.point.line];
@@ -1703,7 +1619,7 @@ impl ansi::Handler for Term {
fn bell(&mut self) {
trace!("Bell");
self.visual_bell.ring();
- self.next_is_urgent = Some(true);
+ self.event_proxy.send_event(Event::Urgent);
}
#[inline]
@@ -1794,12 +1710,14 @@ impl ansi::Handler for Term {
#[inline]
fn delete_chars(&mut self, count: Column) {
+ let cols = self.grid.num_cols();
+
// Ensure deleting within terminal bounds
- let count = min(count, self.size_info.cols());
+ let count = min(count, cols);
let start = self.cursor.point.col;
- let end = min(start + count, self.grid.num_cols() - 1);
- let n = (self.size_info.cols() - end).0;
+ let end = min(start + count, cols - 1);
+ let n = (cols - end).0;
let line = &mut self.grid[self.cursor.point.line];
@@ -1813,7 +1731,7 @@ impl ansi::Handler for Term {
// Clear last `count` cells in line. If deleting 1 char, need to delete
// 1 cell.
let template = self.cursor.template;
- let end = self.size_info.cols() - count;
+ let end = cols - count;
for c in &mut line[end..] {
c.reset(&template);
}
@@ -1983,13 +1901,9 @@ impl ansi::Handler for Term {
self.swap_alt();
}
self.input_needs_wrap = false;
- self.next_title = None;
- self.next_mouse_cursor = None;
self.cursor = Default::default();
self.active_charset = Default::default();
self.mode = Default::default();
- self.font_size = self.original_font_size;
- self.next_is_urgent = None;
self.cursor_save = Default::default();
self.cursor_save_alt = Default::default();
self.colors = self.original_colors;
@@ -2061,15 +1975,15 @@ impl ansi::Handler for Term {
ansi::Mode::CursorKeys => self.mode.insert(TermMode::APP_CURSOR),
ansi::Mode::ReportMouseClicks => {
self.mode.insert(TermMode::MOUSE_REPORT_CLICK);
- self.set_mouse_cursor(MouseCursor::Default);
+ self.event_proxy.send_event(Event::MouseCursorDirty);
},
ansi::Mode::ReportCellMouseMotion => {
self.mode.insert(TermMode::MOUSE_DRAG);
- self.set_mouse_cursor(MouseCursor::Default);
+ self.event_proxy.send_event(Event::MouseCursorDirty);
},
ansi::Mode::ReportAllMouseMotion => {
self.mode.insert(TermMode::MOUSE_MOTION);
- self.set_mouse_cursor(MouseCursor::Default);
+ self.event_proxy.send_event(Event::MouseCursorDirty);
},
ansi::Mode::ReportFocusInOut => self.mode.insert(TermMode::FOCUS_IN_OUT),
ansi::Mode::BracketedPaste => self.mode.insert(TermMode::BRACKETED_PASTE),
@@ -2101,15 +2015,15 @@ impl ansi::Handler for Term {
ansi::Mode::CursorKeys => self.mode.remove(TermMode::APP_CURSOR),
ansi::Mode::ReportMouseClicks => {
self.mode.remove(TermMode::MOUSE_REPORT_CLICK);
- self.set_mouse_cursor(MouseCursor::Text);
+ self.event_proxy.send_event(Event::MouseCursorDirty);
},
ansi::Mode::ReportCellMouseMotion => {
self.mode.remove(TermMode::MOUSE_DRAG);
- self.set_mouse_cursor(MouseCursor::Text);
+ self.event_proxy.send_event(Event::MouseCursorDirty);
},
ansi::Mode::ReportAllMouseMotion => {
self.mode.remove(TermMode::MOUSE_MOTION);
- self.set_mouse_cursor(MouseCursor::Text);
+ self.event_proxy.send_event(Event::MouseCursorDirty);
},
ansi::Mode::ReportFocusInOut => self.mode.remove(TermMode::FOCUS_IN_OUT),
ansi::Mode::BracketedPaste => self.mode.remove(TermMode::BRACKETED_PASTE),
@@ -2215,19 +2129,22 @@ impl IndexMut<Column> for TabStops {
mod tests {
use std::mem;
- use font::Size;
use serde_json;
use crate::ansi::{self, CharsetIndex, Handler, StandardCharset};
use crate::clipboard::Clipboard;
- use crate::config::Config;
+ use crate::config::MockConfig;
+ use crate::event::{Event, EventListener};
use crate::grid::{Grid, Scroll};
use crate::index::{Column, Line, Point, Side};
- use crate::input::FONT_SIZE_STEP;
- use crate::message_bar::MessageBuffer;
use crate::selection::Selection;
use crate::term::{cell, Cell, SizeInfo, Term};
+ struct Mock;
+ impl EventListener for Mock {
+ fn send_event(&self, _event: Event) {}
+ }
+
#[test]
fn semantic_selection_works() {
let size = SizeInfo {
@@ -2239,8 +2156,7 @@ mod tests {
padding_y: 0.0,
dpr: 1.0,
};
- let mut term =
- Term::new(&Default::default(), size, MessageBuffer::new(), Clipboard::new_nop());
+ let mut term = Term::new(&MockConfig::default(), &size, Clipboard::new_nop(), Mock);
let mut grid: Grid<Cell> = Grid::new(Line(3), Column(5), 0, Cell::default());
for i in 0..5 {
for j in 0..2 {
@@ -2284,8 +2200,7 @@ mod tests {
padding_y: 0.0,
dpr: 1.0,
};
- let mut term =
- Term::new(&Default::default(), size, MessageBuffer::new(), Clipboard::new_nop());
+ let mut term = Term::new(&MockConfig::default(), &size, Clipboard::new_nop(), Mock);
let mut grid: Grid<Cell> = Grid::new(Line(1), Column(5), 0, Cell::default());
for i in 0..5 {
grid[Line(0)][Column(i)].c = 'a';
@@ -2310,8 +2225,7 @@ mod tests {
padding_y: 0.0,
dpr: 1.0,
};
- let mut term =
- Term::new(&Default::default(), size, MessageBuffer::new(), Clipboard::new_nop());
+ let mut term = Term::new(&MockConfig::default(), &size, Clipboard::new_nop(), Mock);
let mut grid: Grid<Cell> = Grid::new(Line(3), Column(3), 0, Cell::default());
for l in 0..3 {
if l != 1 {
@@ -2355,8 +2269,7 @@ mod tests {
padding_y: 0.0,
dpr: 1.0,
};
- let mut term =
- Term::new(&Default::default(), size, MessageBuffer::new(), Clipboard::new_nop());
+ let mut term = Term::new(&MockConfig::default(), &size, Clipboard::new_nop(), Mock);
let cursor = Point::new(Line(0), Column(0));
term.configure_charset(CharsetIndex::G0, StandardCharset::SpecialCharacterAndLineDrawing);
term.input('a');
@@ -2364,75 +2277,6 @@ mod tests {
assert_eq!(term.grid()[&cursor].c, '▒');
}
- fn change_font_size_works(font_size: f32) {
- let size = SizeInfo {
- width: 21.0,
- height: 51.0,
- cell_width: 3.0,
- cell_height: 3.0,
- padding_x: 0.0,
- padding_y: 0.0,
- dpr: 1.0,
- };
- let config: Config = Default::default();
- let mut term: Term = Term::new(&config, size, MessageBuffer::new(), Clipboard::new_nop());
- term.change_font_size(font_size);
-
- let expected_font_size: Size = config.font.size + Size::new(font_size);
- assert_eq!(term.font_size, expected_font_size);
- }
-
- #[test]
- fn increase_font_size_works() {
- change_font_size_works(10.0);
- }
-
- #[test]
- fn decrease_font_size_works() {
- change_font_size_works(-10.0);
- }
-
- #[test]
- fn prevent_font_below_threshold_works() {
- let size = SizeInfo {
- width: 21.0,
- height: 51.0,
- cell_width: 3.0,
- cell_height: 3.0,
- padding_x: 0.0,
- padding_y: 0.0,
- dpr: 1.0,
- };
- let config: Config = Default::default();
- let mut term: Term = Term::new(&config, size, MessageBuffer::new(), Clipboard::new_nop());
-
- term.change_font_size(-100.0);
-
- let expected_font_size: Size = Size::new(FONT_SIZE_STEP);
- assert_eq!(term.font_size, expected_font_size);
- }
-
- #[test]
- fn reset_font_size_works() {
- let size = SizeInfo {
- width: 21.0,
- height: 51.0,
- cell_width: 3.0,
- cell_height: 3.0,
- padding_x: 0.0,
- padding_y: 0.0,
- dpr: 1.0,
- };
- let config: Config = Default::default();
- let mut term: Term = Term::new(&config, size, MessageBuffer::new(), Clipboard::new_nop());
-
- term.change_font_size(10.0);
- term.reset_font_size();
-
- let expected_font_size: Size = config.font.size;
- assert_eq!(term.font_size, expected_font_size);
- }
-
#[test]
fn clear_saved_lines() {
let size = SizeInfo {
@@ -2444,8 +2288,7 @@ mod tests {
padding_y: 0.0,
dpr: 1.0,
};
- let config: Config = Default::default();
- let mut term: Term = Term::new(&config, size, MessageBuffer::new(), Clipboard::new_nop());
+ let mut term = Term::new(&MockConfig::default(), &size, Clipboard::new_nop(), Mock);
// Add one line of scrollback
term.grid.scroll_up(&(Line(0)..Line(1)), Line(1), &Cell::default());
@@ -2471,13 +2314,18 @@ mod benches {
use std::path::Path;
use crate::clipboard::Clipboard;
- use crate::config::Config;
+ use crate::config::MockConfig;
+ use crate::event::{Event, EventListener};
use crate::grid::Grid;
- use crate::message_bar::MessageBuffer;
use super::cell::Cell;
use super::{SizeInfo, Term};
+ struct Mock;
+ impl EventListener for Mock {
+ fn send_event(&self, _event: Event) {}
+ }
+
fn read_string<P>(path: P) -> String
where
P: AsRef<Path>,
@@ -2512,13 +2360,13 @@ mod benches {
let mut grid: Grid<Cell> = json::from_str(&serialized_grid).unwrap();
let size: SizeInfo = json::from_str(&serialized_size).unwrap();
- let config = Config::default();
+ let config = MockConfig::default();
- let mut terminal = Term::new(&config, size, MessageBuffer::new(), Clipboard::new_nop());
+ let mut terminal = Term::new(&config, &size, Clipboard::new_nop(), Mock);
mem::swap(&mut terminal.grid, &mut grid);
b.iter(|| {
- let iter = terminal.renderable_cells(&config, false);
+ let iter = terminal.renderable_cells(&config);
for cell in iter {
test::black_box(cell);
}
diff --git a/alacritty_terminal/src/tty/mod.rs b/alacritty_terminal/src/tty/mod.rs
index 16ae96ce..7150a42d 100644
--- a/alacritty_terminal/src/tty/mod.rs
+++ b/alacritty_terminal/src/tty/mod.rs
@@ -77,7 +77,7 @@ pub trait EventedPty: EventedReadWrite {
}
// Setup environment variables
-pub fn setup_env(config: &Config) {
+pub fn setup_env<C>(config: &Config<C>) {
// Default to 'alacritty' terminfo if it is available, otherwise
// default to 'xterm-256color'. May be overridden by user's config
// below.
diff --git a/alacritty_terminal/src/tty/unix.rs b/alacritty_terminal/src/tty/unix.rs
index 77b5db43..a2a277a6 100644
--- a/alacritty_terminal/src/tty/unix.rs
+++ b/alacritty_terminal/src/tty/unix.rs
@@ -15,12 +15,13 @@
//! tty related functionality
use crate::config::{Config, Shell};
-use crate::display::OnResize;
+use crate::event::OnResize;
use crate::term::SizeInfo;
use crate::tty::{ChildEvent, EventedPty, EventedReadWrite};
use mio;
use libc::{self, c_int, pid_t, winsize, TIOCSCTTY};
+use log::error;
use nix::pty::openpty;
use signal_hook::{self as sighook, iterator::Signals};
@@ -42,6 +43,13 @@ use std::sync::atomic::{AtomicUsize, Ordering};
/// Necessary to put this in static storage for `sigchld` to have access
static PID: AtomicUsize = AtomicUsize::new(0);
+macro_rules! die {
+ ($($arg:tt)*) => {{
+ error!($($arg)*);
+ ::std::process::exit(1);
+ }}
+}
+
pub fn child_pid() -> pid_t {
PID.load(Ordering::Relaxed) as pid_t
}
@@ -133,24 +141,8 @@ pub struct Pty {
signals_token: mio::Token,
}
-impl Pty {
- /// Resize the pty
- ///
- /// Tells the kernel that the window size changed with the new pixel
- /// dimensions and line/column counts.
- pub fn resize<T: ToWinsize>(&self, size: &T) {
- let win = size.to_winsize();
-
- let res = unsafe { libc::ioctl(self.fd.as_raw_fd(), libc::TIOCSWINSZ, &win as *const _) };
-
- if res < 0 {
- die!("ioctl TIOCSWINSZ failed: {}", io::Error::last_os_error());
- }
- }
-}
-
/// Create a new tty and return a handle to interact with it.
-pub fn new<T: ToWinsize>(config: &Config, size: &T, window_id: Option<usize>) -> Pty {
+pub fn new<C>(config: &Config<C>, size: &SizeInfo, window_id: Option<usize>) -> Pty {
let win_size = size.to_winsize();
let mut buf = [0; 1024];
let pw = get_pw_entry(&mut buf);
@@ -241,12 +233,10 @@ pub fn new<T: ToWinsize>(config: &Config, size: &T, window_id: Option<usize>) ->
signals,
signals_token: mio::Token::from(0),
};
- pty.resize(size);
+ pty.fd.as_raw_fd().on_resize(size);
pty
},
- Err(err) => {
- die!("Failed to spawn command: {}", err);
- },
+ Err(err) => die!("Failed to spawn command: {}", err),
}
}
@@ -365,6 +355,10 @@ impl<'a> ToWinsize for &'a SizeInfo {
}
impl OnResize for i32 {
+ /// Resize the pty
+ ///
+ /// Tells the kernel that the window size changed with the new pixel
+ /// dimensions and line/column counts.
fn on_resize(&mut self, size: &SizeInfo) {
let win = size.to_winsize();
diff --git a/alacritty_terminal/src/tty/windows/conpty.rs b/alacritty_terminal/src/tty/windows/conpty.rs
index bd602c35..fe49b4dc 100644
--- a/alacritty_terminal/src/tty/windows/conpty.rs
+++ b/alacritty_terminal/src/tty/windows/conpty.rs
@@ -22,6 +22,7 @@ use std::ptr;
use std::sync::Arc;
use dunce::canonicalize;
+use log::info;
use mio_anonymous_pipes::{EventedAnonRead, EventedAnonWrite};
use miow;
use widestring::U16CString;
@@ -38,7 +39,7 @@ use winapi::um::winbase::{EXTENDED_STARTUPINFO_PRESENT, STARTF_USESTDHANDLES, ST
use winapi::um::wincontypes::{COORD, HPCON};
use crate::config::{Config, Shell};
-use crate::display::OnResize;
+use crate::event::OnResize;
use crate::term::SizeInfo;
/// Dynamically-loaded Pseudoconsole API from kernel32.dll
@@ -98,7 +99,11 @@ impl Drop for Conpty {
unsafe impl Send for Conpty {}
unsafe impl Sync for Conpty {}
-pub fn new<'a>(config: &Config, size: &SizeInfo, _window_id: Option<usize>) -> Option<Pty<'a>> {
+pub fn new<'a, C>(
+ config: &Config<C>,
+ size: &SizeInfo,
+ _window_id: Option<usize>,
+) -> Option<Pty<'a>> {
if !config.enable_experimental_conpty_backend {
return None;
}
diff --git a/alacritty_terminal/src/tty/windows/mod.rs b/alacritty_terminal/src/tty/windows/mod.rs
index 7537d331..922dde26 100644
--- a/alacritty_terminal/src/tty/windows/mod.rs
+++ b/alacritty_terminal/src/tty/windows/mod.rs
@@ -20,12 +20,13 @@ use mio::{self, Evented, Poll, PollOpt, Ready, Token};
use mio_anonymous_pipes::{EventedAnonRead, EventedAnonWrite};
use mio_named_pipes::NamedPipe;
+use log::info;
use winapi::shared::winerror::WAIT_TIMEOUT;
use winapi::um::synchapi::WaitForSingleObject;
use winapi::um::winbase::WAIT_OBJECT_0;
use crate::config::Config;
-use crate::display::OnResize;
+use crate::event::OnResize;
use crate::term::SizeInfo;
use crate::tty::{EventedPty, EventedReadWrite};
@@ -83,7 +84,7 @@ impl<'a> Pty<'a> {
}
}
-pub fn new<'a>(config: &Config, size: &SizeInfo, window_id: Option<usize>) -> Pty<'a> {
+pub fn new<'a, C>(config: &Config<C>, size: &SizeInfo, window_id: Option<usize>) -> Pty<'a> {
if let Some(pty) = conpty::new(config, size, window_id) {
info!("Using Conpty agent");
IS_CONPTY.store(true, Ordering::Relaxed);
diff --git a/alacritty_terminal/src/tty/windows/winpty.rs b/alacritty_terminal/src/tty/windows/winpty.rs
index 8795ca6d..db397ad9 100644
--- a/alacritty_terminal/src/tty/windows/winpty.rs
+++ b/alacritty_terminal/src/tty/windows/winpty.rs
@@ -22,13 +22,13 @@ use std::sync::Arc;
use std::u16;
use dunce::canonicalize;
+use log::info;
use mio_named_pipes::NamedPipe;
use winapi::um::winbase::FILE_FLAG_OVERLAPPED;
-use winpty::Config as WinptyConfig;
-use winpty::{ConfigFlags, MouseMode, SpawnConfig, SpawnFlags, Winpty};
+use winpty::{Config as WinptyConfig, ConfigFlags, MouseMode, SpawnConfig, SpawnFlags, Winpty};
use crate::config::{Config, Shell};
-use crate::display::OnResize;
+use crate::event::OnResize;
use crate::term::SizeInfo;
// We store a raw pointer because we need mutable access to call
@@ -75,7 +75,7 @@ impl<'a> Drop for Agent<'a> {
/// This is a placeholder value until we see how often long responses happen
const AGENT_TIMEOUT: u32 = 10000;
-pub fn new<'a>(config: &Config, size: &SizeInfo, _window_id: Option<usize>) -> Pty<'a> {
+pub fn new<'a, C>(config: &Config<C>, size: &SizeInfo, _window_id: Option<usize>) -> Pty<'a> {
// Create config
let mut wconfig = WinptyConfig::new(ConfigFlags::empty()).unwrap();
diff --git a/alacritty_terminal/src/url.rs b/alacritty_terminal/src/url.rs
index 292f8358..9e8ecd4b 100644
--- a/alacritty_terminal/src/url.rs
+++ b/alacritty_terminal/src/url.rs
@@ -29,7 +29,7 @@ impl Url {
}
/// Convert URLs bounding points to linear indices
- pub fn linear_bounds(&self, terminal: &Term) -> RangeInclusive<Linear> {
+ pub fn linear_bounds<T>(&self, terminal: &Term<T>) -> RangeInclusive<Linear> {
let mut start = self.start;
let mut end = self.end;
diff --git a/alacritty_terminal/tests/ref.rs b/alacritty_terminal/tests/ref.rs
index b6efb6a8..1d59e700 100644
--- a/alacritty_terminal/tests/ref.rs
+++ b/alacritty_terminal/tests/ref.rs
@@ -1,5 +1,4 @@
-#[macro_use]
-extern crate serde_derive;
+use serde::Deserialize;
use serde_json as json;
use std::fs::File;
@@ -8,9 +7,9 @@ use std::path::Path;
use alacritty_terminal::ansi;
use alacritty_terminal::clipboard::Clipboard;
-use alacritty_terminal::config::Config;
+use alacritty_terminal::config::MockConfig;
+use alacritty_terminal::event::{Event, EventListener};
use alacritty_terminal::index::Column;
-use alacritty_terminal::message_bar::MessageBuffer;
use alacritty_terminal::term::cell::Cell;
use alacritty_terminal::term::SizeInfo;
use alacritty_terminal::Grid;
@@ -81,6 +80,11 @@ struct RefConfig {
history_size: u32,
}
+struct Mock;
+impl EventListener for Mock {
+ fn send_event(&self, _event: Event) {}
+}
+
fn ref_test(dir: &Path) {
let recording = read_u8(dir.join("alacritty.recording"));
let serialized_size = read_string(dir.join("size.json")).unwrap();
@@ -91,10 +95,10 @@ fn ref_test(dir: &Path) {
let grid: Grid<Cell> = json::from_str(&serialized_grid).unwrap();
let ref_config: RefConfig = json::from_str(&serialized_cfg).unwrap_or_default();
- let mut config: Config = Default::default();
+ let mut config = MockConfig::default();
config.scrolling.set_history(ref_config.history_size);
- let mut terminal = Term::new(&config, size, MessageBuffer::new(), Clipboard::new_nop());
+ let mut terminal = Term::new(&config, &size, Clipboard::new_nop(), Mock);
let mut parser = ansi::Processor::new();
for byte in recording {
diff --git a/font/src/darwin/mod.rs b/font/src/darwin/mod.rs
index 42927654..dae7ee04 100644
--- a/font/src/darwin/mod.rs
+++ b/font/src/darwin/mod.rs
@@ -591,12 +591,11 @@ mod tests {
let index = ((glyph.width * 3 * row) + (col * 3)) as usize;
let value = glyph.buf[index];
let c = match value {
- 0...50 => ' ',
- 51...100 => '.',
- 101...150 => '~',
- 151...200 => '*',
- 201...255 => '#',
- _ => unreachable!(),
+ 0..=50 => ' ',
+ 51..=100 => '.',
+ 101..=150 => '~',
+ 151..=200 => '*',
+ 201..=255 => '#',
};
print!("{}", c);
}
diff --git a/font/src/ft/mod.rs b/font/src/ft/mod.rs
index 5388aeb4..0886f177 100644
--- a/font/src/ft/mod.rs
+++ b/font/src/ft/mod.rs
@@ -546,7 +546,7 @@ pub enum Error {
}
impl ::std::error::Error for Error {
- fn cause(&self) -> Option<&dyn (::std::error::Error)> {
+ fn cause(&self) -> Option<&dyn std::error::Error> {
match *self {
Error::FreeType(ref err) => Some(err),
_ => None,
diff --git a/font/src/lib.rs b/font/src/lib.rs
index d3bddd54..262cf911 100644
--- a/font/src/lib.rs
+++ b/font/src/lib.rs
@@ -47,6 +47,7 @@ extern crate log;
use std::fmt;
use std::hash::{Hash, Hasher};
+use std::ops::{Add, Mul};
use std::sync::atomic::{AtomicUsize, Ordering};
// If target isn't macos or windows, reexport everything from ft
@@ -173,28 +174,42 @@ impl PartialEq for GlyphKey {
pub struct Size(i16);
impl Size {
+ /// Create a new `Size` from a f32 size in points
+ pub fn new(size: f32) -> Size {
+ Size((size * Size::factor()) as i16)
+ }
+
/// Scale factor between font "Size" type and point size
#[inline]
pub fn factor() -> f32 {
2.0
}
- /// Create a new `Size` from a f32 size in points
- pub fn new(size: f32) -> Size {
- Size((size * Size::factor()) as i16)
- }
-
/// Get the f32 size in points
pub fn as_f32_pts(self) -> f32 {
f32::from(self.0) / Size::factor()
}
}
-impl ::std::ops::Add for Size {
+impl<T: Into<Size>> Add<T> for Size {
type Output = Size;
- fn add(self, other: Size) -> Size {
- Size(self.0.saturating_add(other.0))
+ fn add(self, other: T) -> Size {
+ Size(self.0.saturating_add(other.into().0))
+ }
+}
+
+impl<T: Into<Size>> Mul<T> for Size {
+ type Output = Size;
+
+ fn mul(self, other: T) -> Size {
+ Size(self.0 * other.into().0)
+ }
+}
+
+impl From<f32> for Size {
+ fn from(float: f32) -> Size {
+ Size::new(float)
}
}