makepad_platform/os/windows/windows_stdin.rs
1use {
2 std::{
3 io,
4 io::prelude::*,
5 io::BufReader,
6 },
7 crate::{
8 makepad_live_id::*,
9 makepad_math::*,
10 makepad_micro_serde::*,
11 event::Event,
12 window::CxWindowPool,
13 event::WindowGeom,
14 CxOsApi,
15 texture::{Texture, TextureFormat},
16 thread::SignalToUI,
17 os::{
18 win32_app::{Win32Time},
19 d3d11::D3d11Cx,
20 cx_stdin::{HostToStdin, PresentableDraw, StdinToHost, Swapchain},
21 },
22 pass::{CxPassParent},
23 cx_api::CxOsOp,
24 cx::Cx,
25 windows::Win32::Foundation::HANDLE,
26 }
27};
28
29#[derive(Default)]
30pub(crate) struct StdinWindow{
31 swapchain: Option<Swapchain<Texture>>,
32 present_index: usize,
33 new_frame_being_rendered: Option<PresentableDraw>
34}
35
36
37impl Cx {
38
39 pub (crate) fn stdin_handle_repaint(
40 &mut self,
41 d3d11_cx: &mut D3d11Cx,
42 windows: &mut Vec<StdinWindow>,
43 time: &Win32Time,
44 ) {
45 let mut passes_todo = Vec::new();
46 self.compute_pass_repaint_order(&mut passes_todo);
47 self.repaint_id += 1;
48 let time_now = time.time_now();
49 for &pass_id in &passes_todo {
50 self.passes[pass_id].set_time(time_now as f32);
51 match self.passes[pass_id].parent.clone() {
52 CxPassParent::Xr => {}
53 CxPassParent::Window(window_id) => {
54 // only render to swapchain if swapchain exists
55 let window = &mut windows[window_id.id()];
56 if let Some(swapchain) = &window.swapchain {
57
58 // and if GPU is not already rendering something else
59 if window.new_frame_being_rendered.is_none() {
60 let current_image = &swapchain.presentable_images[window.present_index];
61
62 window.present_index = (window.present_index + 1) % swapchain.presentable_images.len();
63
64 // render to swapchain
65 self.draw_pass_to_texture(pass_id, d3d11_cx, Some(current_image.image.texture_id()));
66
67 let dpi_factor = self.passes[pass_id].dpi_factor.unwrap();
68 let pass_rect = self.get_pass_rect(pass_id, dpi_factor).unwrap();
69 let future_presentable_draw = PresentableDraw {
70 window_id: window_id.id(),
71 target_id: current_image.id,
72 width: (pass_rect.size.x * dpi_factor) as u32,
73 height: (pass_rect.size.y * dpi_factor) as u32,
74 };
75
76 // start GPU event query
77 d3d11_cx.start_querying();
78
79 // and inform event_loop to go poll GPU readiness
80 window.new_frame_being_rendered = Some(future_presentable_draw);
81 }
82 }
83 }
84 CxPassParent::Pass(_) => {
85 //let dpi_factor = self.get_delegated_dpi_factor(parent_pass_id);
86 self.draw_pass_to_texture(pass_id, d3d11_cx, None);
87 },
88 CxPassParent::None => {
89 self.draw_pass_to_texture(pass_id, d3d11_cx, None);
90 }
91 }
92 }
93 }
94
95 pub fn stdin_event_loop(&mut self, d3d11_cx: &mut D3d11Cx) {
96
97 let (json_msg_tx, json_msg_rx) = std::sync::mpsc::channel();
98 {
99 std::thread::spawn(move || {
100 let mut reader = BufReader::new(std::io::stdin().lock());
101 let mut line = String::new();
102 loop {
103 line.clear();
104 if let Ok(0) | Err(_) = reader.read_line(&mut line) {
105 break;
106 }
107
108 // alright lets put the line in a json parser
109 match HostToStdin::deserialize_json(&line) {
110 Ok(msg) => {
111 if json_msg_tx.send(msg).is_err() {
112 break;
113 }
114 }
115 Err(err) => {
116 // we should output a log string
117 crate::error!("Cant parse stdin-JSON {} {:?}", line, err)
118 }
119 }
120 }
121 });
122 }
123
124 let _ = io::stdout().write_all(StdinToHost::ReadyToStart.to_json().as_bytes());
125
126 let mut stdin_windows:Vec<StdinWindow> = Vec::new();
127 let time = Win32Time::new();
128
129 self.call_event_handler(&Event::Startup);
130
131 //let mut previous_tick_time_s: Option<f64> = None;
132 //let mut previous_elapsed_s = 0f64;
133 //let mut allow_rendering = true;
134
135 while let Ok(msg) = json_msg_rx.recv() {
136
137 match msg {
138 HostToStdin::KeyDown(e) => {
139 self.call_event_handler(&Event::KeyDown(e));
140 }
141 HostToStdin::KeyUp(e) => {
142 self.call_event_handler(&Event::KeyUp(e));
143 }
144 HostToStdin::TextInput(e) => {
145 self.call_event_handler(&Event::TextInput(e));
146 }
147 HostToStdin::MouseDown(e) => {
148 self.fingers.process_tap_count(
149 dvec2(e.x, e.y),
150 e.time
151 );
152 let (window_id, pos) = self.windows.window_id_contains(dvec2(e.x, e.y));
153 let mouse_down_event = e.into_event(window_id, pos);
154 self.fingers.mouse_down(mouse_down_event.button, window_id);
155 self.call_event_handler(&Event::MouseDown(mouse_down_event));
156 }
157 HostToStdin::MouseMove(e) => {
158 let (window_id, pos) = if let Some((_, window_id)) = self.fingers.first_mouse_button{
159 (window_id, self.windows[window_id].window_geom.position)
160 }
161 else{
162 self.windows.window_id_contains(dvec2(e.x, e.y))
163 };
164 self.call_event_handler(&Event::MouseMove(e.into_event(window_id, pos)));
165 self.fingers.cycle_hover_area(live_id!(mouse).into());
166 self.fingers.switch_captures();
167 }
168 HostToStdin::MouseUp(e) => {
169 let (window_id, pos) = if let Some((_, window_id)) = self.fingers.first_mouse_button{
170 (window_id, self.windows[window_id].window_geom.position)
171 }
172 else{
173 self.windows.window_id_contains(dvec2(e.x, e.y))
174 };
175 let mouse_up_event = e.into_event(window_id, pos);
176 let button = mouse_up_event.button;
177 self.call_event_handler(&Event::MouseUp(mouse_up_event));
178 self.fingers.mouse_up(button);
179 self.fingers.cycle_hover_area(live_id!(mouse).into());
180 }
181 HostToStdin::Scroll(e) => {
182 let (window_id,pos) = self.windows.window_id_contains(dvec2(e.x, e.y));
183 self.call_event_handler(&Event::Scroll(e.into_event(window_id, pos)));
184 }
185 HostToStdin::WindowGeomChange { dpi_factor, left, top, width, height, window_id } => {
186 self.windows[CxWindowPool::from_usize(window_id)].window_geom = WindowGeom {
187 dpi_factor,
188 position: dvec2(left, top),
189 inner_size: dvec2(width, height),
190 ..Default::default()
191 };
192 self.redraw_all();
193 }
194 HostToStdin::Swapchain(new_swapchain) => {
195 let new_swapchain = new_swapchain.images_map(|pi| {
196 let handle = HANDLE(pi.image as isize);
197
198 let format = TextureFormat::SharedBGRAu8 {
199 id: pi.id,
200 width: new_swapchain.alloc_width as usize,
201 height: new_swapchain.alloc_height as usize,
202 initial: true,
203 };
204 let texture = Texture::new_with_format(self, format);
205 self.textures[texture.texture_id()].update_from_shared_handle(d3d11_cx, handle);
206 texture
207 });
208 let window_id = new_swapchain.window_id;
209 let stdin_window = &mut stdin_windows[window_id];
210 stdin_window.swapchain = Some(new_swapchain);
211 stdin_window.present_index = 0;
212
213 self.redraw_all();
214 self.stdin_handle_platform_ops(&mut stdin_windows);
215 }
216 HostToStdin::Tick => {
217
218 // probe current time
219 //let start_time = ::std::time::SystemTime::now();
220
221 // poll the service for updates
222 // check signals
223 if SignalToUI::check_and_clear_ui_signal() {
224 self.handle_media_signals();
225 self.call_event_handler(&Event::Signal);
226 }
227 if SignalToUI::check_and_clear_action_signal() {
228 self.handle_action_receiver();
229 }
230
231 if self.handle_live_edit() {
232 self.call_event_handler(&Event::LiveEdit);
233 self.redraw_all();
234 }
235 self.handle_networking_events();
236 // we should poll our runloop
237 self.stdin_handle_platform_ops(&mut stdin_windows);
238
239 // alright a tick.
240 // we should now run all the stuff.
241 if self.new_next_frames.len() != 0 {
242 self.call_next_frame_event(self.seconds_since_app_start());
243 }
244
245 if self.need_redrawing() {
246 self.call_draw_event();
247 self.hlsl_compile_shaders(d3d11_cx);
248 }
249
250 // repaint
251 self.stdin_handle_repaint(d3d11_cx, &mut stdin_windows, &time);
252
253 // only allow rendering if it didn't take too much time last time
254 //if allow_rendering {
255
256 // check if GPU is ready to flip frames
257 for window in &mut stdin_windows{
258 if let Some(presentable_draw) = window.new_frame_being_rendered {
259 while !d3d11_cx.is_gpu_done() {
260 std::thread::sleep(std::time::Duration::from_millis(3));
261 }
262 let _ = io::stdout().write_all(StdinToHost::DrawCompleteAndFlip(presentable_draw).to_json().as_bytes());
263 window.new_frame_being_rendered = None;
264 }
265 }
266 //}
267
268 // probe how long this took
269 /*
270 let elapsed_s = (start_time.elapsed().unwrap().as_nanos() as f64) / 1000000000.0;
271
272 if let Some(previous_tick_time_s) = previous_tick_time_s {
273
274 // calculate time difference as dictated by the ticks
275 let previous_dtick_s = time - previous_tick_time_s;
276
277 // if this time difference is smaller than the elapsed time, disallow rendering
278 allow_rendering = previous_dtick_s > previous_elapsed_s;
279 }
280
281 // store current tick time and elapsed time
282 previous_tick_time_s = Some(time);
283 previous_elapsed_s = elapsed_s;*/
284 }
285 }
286 }
287 }
288
289 fn stdin_handle_platform_ops(
290 &mut self,
291 stdin_windows:&mut Vec<StdinWindow>,
292 ) {
293 while let Some(op) = self.platform_ops.pop() {
294 match op {
295 CxOsOp::CreateWindow(window_id) => {
296 while window_id.id() >= stdin_windows.len(){
297 stdin_windows.push(StdinWindow::default());
298 }
299 //let stdin_window = &mut stdin_windows[window_id.id()];
300 let window = &mut self.windows[window_id];
301 window.is_created = true;
302 let _ = io::stdout().write_all(StdinToHost::CreateWindow{window_id:window_id.id(),kind_id:window.kind_id}.to_json().as_bytes());
303
304 // lets set up our render pass target
305 /* let pass = &mut self.passes[window.main_pass_id.unwrap()];
306 if let Some(swapchain) = swapchain {
307 pass.color_textures = vec![CxPassColorTexture {
308 clear_color: PassClearColor::ClearWith(vec4(1.0, 1.0, 0.0, 1.0)),
309 //clear_color: PassClearColor::ClearWith(pass.clear_color),
310 texture: swapchain.presentable_images[present_index].image.clone(),
311 }];
312 }*/
313 },
314 CxOsOp::SetCursor(cursor) => {
315 let _ = io::stdout().write_all(StdinToHost::SetCursor(cursor).to_json().as_bytes());
316 },
317 _ => ()
318 /*
319 CxOsOp::CloseWindow(_window_id) => {},
320 CxOsOp::MinimizeWindow(_window_id) => {},
321 CxOsOp::MaximizeWindow(_window_id) => {},
322 CxOsOp::RestoreWindow(_window_id) => {},
323 CxOsOp::FullscreenWindow(_window_id) => {},
324 CxOsOp::NormalizeWindow(_window_id) => {}
325 CxOsOp::SetTopmost(_window_id, _is_topmost) => {}
326 CxOsOp::XrStartPresenting(_) => {},
327 CxOsOp::XrStopPresenting(_) => {},
328 CxOsOp::ShowTextIME(_area, _pos) => {},
329 CxOsOp::HideTextIME => {},
330 CxOsOp::SetCursor(_cursor) => {},
331 CxOsOp::StartTimer {timer_id, interval, repeats} => {},
332 CxOsOp::StopTimer(timer_id) => {},
333 CxOsOp::StartDragging(dragged_item) => {}
334 CxOsOp::UpdateMenu(menu) => {}*/
335 }
336 }
337 }
338
339}