summaryrefslogtreecommitdiff
path: root/alacritty_terminal/src/tty/windows/automatic_backend.rs
diff options
context:
space:
mode:
Diffstat (limited to 'alacritty_terminal/src/tty/windows/automatic_backend.rs')
-rw-r--r--alacritty_terminal/src/tty/windows/automatic_backend.rs189
1 files changed, 189 insertions, 0 deletions
diff --git a/alacritty_terminal/src/tty/windows/automatic_backend.rs b/alacritty_terminal/src/tty/windows/automatic_backend.rs
new file mode 100644
index 00000000..74a546dd
--- /dev/null
+++ b/alacritty_terminal/src/tty/windows/automatic_backend.rs
@@ -0,0 +1,189 @@
+/// Types to determine the appropriate PTY backend at runtime.
+///
+/// Unless the winpty feature is disabled, the PTY backend will automatically fall back to
+/// WinPTY when the newer ConPTY API is not supported, as long as the user hasn't explicitly
+/// opted into the WinPTY config option.
+use std::io::{self, Read, Write};
+
+use log::info;
+use mio::{Evented, Poll, PollOpt, Ready, Token};
+use mio_anonymous_pipes::{EventedAnonRead, EventedAnonWrite};
+use mio_named_pipes::NamedPipe;
+
+use crate::config::Config;
+use crate::event::OnResize;
+use crate::term::SizeInfo;
+
+use super::{conpty, winpty, Pty};
+
+pub fn new<C>(config: &Config<C>, size: &SizeInfo, window_id: Option<usize>) -> Pty {
+ if let Some(pty) = conpty::new(config, size, window_id) {
+ info!("Using ConPTY backend");
+ pty
+ } else {
+ info!("Using WinPTY backend");
+ winpty::new(config, size, window_id)
+ }
+}
+
+pub enum PtyBackend {
+ Winpty(winpty::Agent),
+ Conpty(conpty::Conpty),
+}
+
+impl OnResize for PtyBackend {
+ fn on_resize(&mut self, size: &SizeInfo) {
+ match self {
+ PtyBackend::Winpty(w) => w.on_resize(size),
+ PtyBackend::Conpty(c) => c.on_resize(size),
+ }
+ }
+}
+
+// TODO: The ConPTY API currently must use synchronous pipes as the input
+// and output handles. This has led to the need to support two different
+// types of pipe.
+//
+// When https://github.com/Microsoft/console/issues/262 lands then the
+// Anonymous variant of this enum can be removed from the codebase and
+// everything can just use NamedPipe.
+pub enum EventedReadablePipe {
+ Anonymous(EventedAnonRead),
+ Named(NamedPipe),
+}
+
+pub enum EventedWritablePipe {
+ Anonymous(EventedAnonWrite),
+ Named(NamedPipe),
+}
+
+impl Evented for EventedReadablePipe {
+ fn register(
+ &self,
+ poll: &Poll,
+ token: Token,
+ interest: Ready,
+ opts: PollOpt,
+ ) -> io::Result<()> {
+ match self {
+ EventedReadablePipe::Anonymous(p) => p.register(poll, token, interest, opts),
+ EventedReadablePipe::Named(p) => p.register(poll, token, interest, opts),
+ }
+ }
+
+ fn reregister(
+ &self,
+ poll: &Poll,
+ token: Token,
+ interest: Ready,
+ opts: PollOpt,
+ ) -> io::Result<()> {
+ match self {
+ EventedReadablePipe::Anonymous(p) => p.reregister(poll, token, interest, opts),
+ EventedReadablePipe::Named(p) => p.reregister(poll, token, interest, opts),
+ }
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ match self {
+ EventedReadablePipe::Anonymous(p) => p.deregister(poll),
+ EventedReadablePipe::Named(p) => p.deregister(poll),
+ }
+ }
+}
+
+impl Read for EventedReadablePipe {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ match self {
+ EventedReadablePipe::Anonymous(p) => p.read(buf),
+ EventedReadablePipe::Named(p) => p.read(buf),
+ }
+ }
+}
+
+impl Evented for EventedWritablePipe {
+ fn register(
+ &self,
+ poll: &Poll,
+ token: Token,
+ interest: Ready,
+ opts: PollOpt,
+ ) -> io::Result<()> {
+ match self {
+ EventedWritablePipe::Anonymous(p) => p.register(poll, token, interest, opts),
+ EventedWritablePipe::Named(p) => p.register(poll, token, interest, opts),
+ }
+ }
+
+ fn reregister(
+ &self,
+ poll: &Poll,
+ token: Token,
+ interest: Ready,
+ opts: PollOpt,
+ ) -> io::Result<()> {
+ match self {
+ EventedWritablePipe::Anonymous(p) => p.reregister(poll, token, interest, opts),
+ EventedWritablePipe::Named(p) => p.reregister(poll, token, interest, opts),
+ }
+ }
+
+ fn deregister(&self, poll: &Poll) -> io::Result<()> {
+ match self {
+ EventedWritablePipe::Anonymous(p) => p.deregister(poll),
+ EventedWritablePipe::Named(p) => p.deregister(poll),
+ }
+ }
+}
+
+impl Write for EventedWritablePipe {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ match self {
+ EventedWritablePipe::Anonymous(p) => p.write(buf),
+ EventedWritablePipe::Named(p) => p.write(buf),
+ }
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ match self {
+ EventedWritablePipe::Anonymous(p) => p.flush(),
+ EventedWritablePipe::Named(p) => p.flush(),
+ }
+ }
+}
+
+impl From<winpty::Agent> for PtyBackend {
+ fn from(inner: winpty::Agent) -> Self {
+ PtyBackend::Winpty(inner)
+ }
+}
+
+impl From<conpty::Conpty> for PtyBackend {
+ fn from(inner: conpty::Conpty) -> Self {
+ PtyBackend::Conpty(inner)
+ }
+}
+
+impl From<EventedAnonRead> for EventedReadablePipe {
+ fn from(inner: EventedAnonRead) -> Self {
+ EventedReadablePipe::Anonymous(inner)
+ }
+}
+
+impl From<NamedPipe> for EventedReadablePipe {
+ fn from(inner: NamedPipe) -> Self {
+ EventedReadablePipe::Named(inner)
+ }
+}
+
+impl From<EventedAnonWrite> for EventedWritablePipe {
+ fn from(inner: EventedAnonWrite) -> Self {
+ EventedWritablePipe::Anonymous(inner)
+ }
+}
+
+impl From<NamedPipe> for EventedWritablePipe {
+ fn from(inner: NamedPipe) -> Self {
+ EventedWritablePipe::Named(inner)
+ }
+}