makepad_platform/os/linux/x11/
linux_x11_stdin.rs

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