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