1use crate::state::Session;
2use crate::wire::{Decoder, Message, Outgoing};
3use crate::*;
4use std::os::fd::{AsRawFd, RawFd};
5use std::os::unix::net::UnixStream;
6use std::time::Instant;
7
8#[derive(Clone, Debug, Eq, PartialEq)]
9pub enum Event {
10 Configured(Configure),
11 FrameAccepted {
12 frame_serial: u64,
13 configure_serial: u64,
14 },
15 FrameDiscarded {
16 frame_serial: u64,
17 configure_serial: u64,
18 },
19 Input(Input),
20 CloseRequested,
21}
22pub struct Client {
24 stream: UnixStream,
25 state: Session,
26 decoder: Decoder,
27 outgoing: Option<Outgoing>,
28 deadline: Option<Instant>,
29 partial_since: Option<Instant>,
30 failed: bool,
31 options: ClientOptions,
32 options_negotiated: bool,
33}
34impl Client {
35 pub fn connect(path: &Path, create: Create) -> io::Result<Self> {
36 Self::connect_with_options(path, create, ClientOptions::default())
37 }
38 pub fn connect_with_options(
41 path: &Path,
42 create: Create,
43 options: ClientOptions,
44 ) -> io::Result<Self> {
45 create.validate()?;
46 let stream = crate::platform::connect_local(path)?;
47 Ok(Self {
48 stream,
49 state: Session::default(),
50 decoder: Decoder::new(false, None),
51 outgoing: Some(Outgoing::new(if options == ClientOptions::default() {
52 Message::Create(create)
53 } else {
54 Message::CreateWithOptions(create, options)
55 })?),
56 deadline: Some(Instant::now() + TRANSFER_TIMEOUT),
57 partial_since: None,
58 failed: false,
59 options,
60 options_negotiated: false,
61 })
62 }
63 pub fn relative_pointer_enabled(&self) -> bool {
65 !self.failed && self.options_negotiated && self.options.relative_pointer
66 }
67 pub fn configuration(&self) -> Option<Configure> {
68 self.state.configuration()
69 }
70 pub fn can_submit(&self) -> bool {
71 !self.failed
72 && self.configuration().is_some()
73 && self.state.inflight.is_none()
74 && self.outgoing.is_none()
75 }
76 pub fn wants_write(&self) -> bool {
77 self.outgoing.is_some()
78 }
79 pub fn submit(&mut self, frame: Frame) -> io::Result<()> {
80 if self.failed {
81 return Err(io::ErrorKind::BrokenPipe.into());
82 }
83 if self.outgoing.is_some() {
84 return Err(io::ErrorKind::WouldBlock.into());
85 }
86 self.state.validate_submit(&frame)?;
87 let outgoing = Outgoing::new(Message::Frame(frame.clone()))?;
88 self.state.submit(&frame)?;
89 self.outgoing = Some(outgoing);
90 self.deadline = Some(Instant::now() + TRANSFER_TIMEOUT);
91 Ok(())
92 }
93 pub fn poll(&mut self) -> io::Result<Vec<Event>> {
94 if self.failed {
95 return Err(io::ErrorKind::BrokenPipe.into());
96 }
97 let result = self.poll_inner();
98 if result.is_err() {
99 self.failed = true;
100 self.outgoing = None;
101 }
102 result
103 }
104 fn poll_inner(&mut self) -> io::Result<Vec<Event>> {
105 let now = Instant::now();
106 if self.deadline.is_some_and(|d| now >= d)
107 || self
108 .partial_since
109 .is_some_and(|start| now.duration_since(start) >= TRANSFER_TIMEOUT)
110 {
111 return Err(io::ErrorKind::TimedOut.into());
112 }
113 let upload_complete = self
114 .outgoing
115 .as_mut()
116 .map(|outgoing| outgoing.flush(&mut self.stream, 1024 * 1024))
117 .transpose()?
118 .unwrap_or(false);
119 if upload_complete {
120 self.outgoing = None;
121 }
122 let mut events = Vec::new();
123 for _ in 0..64 {
124 let Some(message) = self.decoder.poll(&mut self.stream, 4096)? else {
125 break;
126 };
127 self.partial_since = None;
128 let event = match message {
129 Message::Configure(c) if self.options == ClientOptions::default() => {
130 self.state.configure(c)?;
131 if self.state.inflight.is_none() {
132 self.deadline = None;
133 }
134 Event::Configured(c)
135 }
136 Message::ConfigureWithOptions(c, options)
137 if self.options != ClientOptions::default() && options == self.options =>
138 {
139 self.state.configure(c)?;
140 self.options_negotiated = true;
141 if self.state.inflight.is_none() {
142 self.deadline = None;
143 }
144 Event::Configured(c)
145 }
146 Message::Accepted(frame_serial, configure_serial)
147 | Message::Discarded(frame_serial, configure_serial) => {
148 if self.outgoing.is_some() {
149 return Err(invalid("native window ACK precedes complete upload"));
150 }
151 let accepted = matches!(message, Message::Accepted(..));
152 self.state
153 .acknowledge(frame_serial, configure_serial, accepted)?;
154 self.deadline = None;
155 if accepted {
156 Event::FrameAccepted {
157 frame_serial,
158 configure_serial,
159 }
160 } else {
161 Event::FrameDiscarded {
162 frame_serial,
163 configure_serial,
164 }
165 }
166 }
167 Message::Input(input) => {
168 if matches!(input.event, InputEvent::RelativeMotion { .. })
169 && !self.relative_pointer_enabled()
170 {
171 return Err(invalid("unnegotiated native relative pointer input"));
172 }
173 self.state.input(input.clone())?;
174 Event::Input(input)
175 }
176 Message::CloseRequested => Event::CloseRequested,
177 _ => return Err(invalid("unexpected native window server message")),
178 };
179 events.push(event);
180 }
181 if self.decoder.partial() {
182 self.partial_since.get_or_insert(now);
183 } else {
184 self.partial_since = None;
185 }
186 Ok(events)
187 }
188}
189impl AsRawFd for Client {
190 fn as_raw_fd(&self) -> RawFd {
191 self.stream.as_raw_fd()
192 }
193}