makepad_platform/os/linux/x11/
linux_x11.rs

1use {
2    std::cell::RefCell,
3    std::rc::Rc,
4    self::super::opengl_x11::{
5        OpenglWindow,
6        OpenglCx
7    },
8    self::super::super::{
9        egl_sys,
10        x11::xlib_event::*,
11        x11::xlib_app::*,
12        linux_media::CxLinuxMedia
13    },
14    crate::{
15        cx_api::{CxOsOp, CxOsApi}, 
16        makepad_math::dvec2,
17        makepad_live_id::*,
18        thread::Signal,
19        event::Event,
20        pass::CxPassParent,
21        cx::{Cx, OsType,LinuxWindowParams}, 
22        gpu_info::GpuPerformance,
23        os::cx_native::EventFlow,
24    }
25};
26
27impl Cx {
28    pub fn event_loop(cx:Rc<RefCell<Cx>>) {
29        cx.borrow_mut().self_ref = Some(cx.clone());
30        cx.borrow_mut().os_type = OsType::LinuxWindow(LinuxWindowParams{
31            custom_window_chrome: false
32        });
33        cx.borrow_mut().gpu_info.performance = GpuPerformance::Tier1;
34
35        let opengl_windows = Rc::new(RefCell::new(Vec::new()));
36        let is_stdin_loop = std::env::args().find(|v| v=="--stdin-loop").is_some();
37        init_xlib_app_global(Box::new({
38            let cx = cx.clone();
39            move | xlib_app,
40            events | {
41                if is_stdin_loop{
42                    return EventFlow::Wait
43                }
44                let mut cx = cx.borrow_mut();
45                let mut opengl_windows = opengl_windows.borrow_mut();
46                cx.xlib_event_callback(xlib_app, events, &mut *opengl_windows)
47            }
48        }));
49        
50        cx.borrow_mut().os.opengl_cx = Some(unsafe {
51            OpenglCx::from_egl_platform_display(
52                egl_sys::EGL_PLATFORM_X11_EXT,
53                get_xlib_app_global().display,
54            )
55        });
56        
57        if is_stdin_loop {
58            return cx.borrow_mut().stdin_event_loop();
59        }
60        
61        cx.borrow_mut().call_event_handler(&Event::Construct);
62        cx.borrow_mut().redraw_all();
63        get_xlib_app_global().start_timer(0,0.008,true);
64        get_xlib_app_global().event_loop();
65    }
66    
67    fn xlib_event_callback(
68        &mut self,
69        xlib_app: &mut XlibApp, 
70        event: XlibEvent,
71        opengl_windows: &mut Vec<OpenglWindow>
72    ) -> EventFlow {
73        if let EventFlow::Exit = self.handle_platform_ops(opengl_windows, xlib_app) {
74            return EventFlow::Exit
75        }
76        
77        let mut paint_dirty = false;
78        
79        //self.process_desktop_pre_event(&mut event);
80        match event {
81            XlibEvent::AppGotFocus => { // repaint all window passes. Metal sometimes doesnt flip buffers when hidden/no focus
82                for window in opengl_windows.iter_mut() {
83                    if let Some(main_pass_id) = self.windows[window.window_id].main_pass_id {
84                        self.repaint_pass(main_pass_id);
85                    }
86                }
87                paint_dirty = true;
88                self.call_event_handler(&Event::AppGotFocus);
89            }
90            XlibEvent::AppLostFocus => { 
91                self.call_event_handler(&Event::AppLostFocus);
92            }
93            XlibEvent::WindowGeomChange(re) => { // do this here because mac
94                if let Some(window) = opengl_windows.iter_mut().find( | w | w.window_id == re.window_id) {
95                    window.window_geom = re.new_geom.clone();
96                    self.windows[re.window_id].window_geom = re.new_geom.clone();
97                    // redraw just this windows root draw list
98                    if re.old_geom.inner_size != re.new_geom.inner_size {
99                        if let Some(main_pass_id) = self.windows[re.window_id].main_pass_id {
100                            self.redraw_pass_and_child_passes(main_pass_id);
101                        }
102                    }
103                }
104                // ok lets not redraw all, just this window
105                self.call_event_handler(&Event::WindowGeomChange(re));
106            }
107            XlibEvent::WindowClosed(wc) => {
108                let window_id = wc.window_id;
109                self.call_event_handler(&Event::WindowClosed(wc));
110                // lets remove the window from the set
111                self.windows[window_id].is_created = false;
112                if let Some(index) = opengl_windows.iter().position( | w | w.window_id == window_id) {
113                    opengl_windows.remove(index);
114                    if opengl_windows.len() == 0 {
115                        xlib_app.terminate_event_loop();
116                        self.call_event_handler(&Event::Destruct);
117                        return EventFlow::Exit
118                    }
119                }
120            }
121            XlibEvent::Paint => {
122                if self.new_next_frames.len() != 0 {
123                    self.call_next_frame_event(xlib_app.time_now());
124                }
125                if self.need_redrawing() {
126                    self.call_draw_event();
127                    self.os.opengl_cx.as_ref().unwrap().make_current();
128                    self.opengl_compile_shaders();
129                }
130                // ok here we send out to all our childprocesses
131                
132                self.handle_repaint(opengl_windows);
133            }
134            XlibEvent::MouseDown(e) => {
135                self.fingers.process_tap_count(
136                    e.abs,
137                    e.time
138                );
139                self.fingers.mouse_down(e.button);
140                self.call_event_handler(&Event::MouseDown(e.into()))
141            }
142            XlibEvent::MouseMove(e) => {
143                self.call_event_handler(&Event::MouseMove(e.into()));
144                self.fingers.cycle_hover_area(live_id!(mouse).into());
145                self.fingers.switch_captures();
146            }
147            XlibEvent::MouseUp(e) => {
148                let button = e.button;
149                self.call_event_handler(&Event::MouseUp(e.into()));
150                self.fingers.mouse_up(button);
151                self.fingers.cycle_hover_area(live_id!(mouse).into());
152            }
153            XlibEvent::Scroll(e) => {
154                self.call_event_handler(&Event::Scroll(e.into()))
155            }
156            XlibEvent::WindowDragQuery(e) => {
157                self.call_event_handler(&Event::WindowDragQuery(e))
158            }
159            XlibEvent::WindowCloseRequested(e) => {
160                self.call_event_handler(&Event::WindowCloseRequested(e))
161            }
162            XlibEvent::TextInput(e) => {
163                self.call_event_handler(&Event::TextInput(e))
164            }
165            XlibEvent::Drag(e) => {
166                self.call_event_handler(&Event::Drag(e))
167            }
168            XlibEvent::Drop(e) => {
169                self.call_event_handler(&Event::Drop(e))
170            }
171            XlibEvent::DragEnd => {
172                self.call_event_handler(&Event::DragEnd)
173            }
174            XlibEvent::KeyDown(e) => {
175                self.keyboard.process_key_down(e.clone());
176                self.call_event_handler(&Event::KeyDown(e))
177            }
178            XlibEvent::KeyUp(e) => {
179                self.keyboard.process_key_up(e.clone());
180                self.call_event_handler(&Event::KeyUp(e))
181            }
182            XlibEvent::TextCopy(e) => {
183                self.call_event_handler(&Event::TextCopy(e))
184            }
185            XlibEvent::TextCut(e) => {
186                self.call_event_handler(&Event::TextCut(e))
187            }
188            XlibEvent::Timer(e) => {
189                //println!("TIMER! {:?}", std::time::Instant::now());
190                if e.timer_id == 0{
191                    if Signal::check_and_clear_ui_signal(){
192                        self.handle_media_signals();
193                        self.call_event_handler(&Event::Signal);
194                    }
195                }
196                else{
197                    self.call_event_handler(&Event::Timer(e))
198                }
199            }
200        }
201        
202        if self.any_passes_dirty() || self.need_redrawing() || self.new_next_frames.len() != 0 || paint_dirty {
203            EventFlow::Poll
204        } else {
205            EventFlow::Wait
206        }
207        
208    }
209
210    pub(crate) fn handle_networking_events(&mut self) {
211    }
212    
213    pub (crate) fn handle_repaint(&mut self, opengl_windows: &mut Vec<OpenglWindow>) {
214        self.os.opengl_cx.as_ref().unwrap().make_current();
215        let mut passes_todo = Vec::new();
216        self.compute_pass_repaint_order(&mut passes_todo);
217        self.repaint_id += 1;
218        for pass_id in &passes_todo {
219            self.passes[*pass_id].set_time(get_xlib_app_global().time_now() as f32);
220            match self.passes[*pass_id].parent.clone() {
221                CxPassParent::Window(window_id) => {
222                    if let Some(window) = opengl_windows.iter_mut().find( | w | w.window_id == window_id) {
223                        //let dpi_factor = window.window_geom.dpi_factor;
224                        window.resize_buffers();
225                        self.draw_pass_to_window(*pass_id, window);
226                    }
227                }
228                CxPassParent::Pass(_) => {
229                    //let dpi_factor = self.get_delegated_dpi_factor(parent_pass_id);
230                    self.draw_pass_to_magic_texture(*pass_id);
231                },
232                CxPassParent::None => {
233                    self.draw_pass_to_magic_texture(*pass_id);
234                }
235            }
236        }
237    }
238    
239    fn handle_platform_ops(&mut self, opengl_windows: &mut Vec<OpenglWindow>, xlib_app: &mut XlibApp) -> EventFlow {
240        let mut ret = EventFlow::Poll;
241        while let Some(op) = self.platform_ops.pop() {
242            match op {
243                CxOsOp::CreateWindow(window_id) => {
244                    let window = &mut self.windows[window_id];
245                    let opengl_window = OpenglWindow::new(
246                        window_id,
247                        self.os.opengl_cx.as_ref().unwrap(),
248                        window.create_inner_size.unwrap_or(dvec2(800., 600.)),
249                        window.create_position,
250                        &window.create_title,
251                    );
252                    window.window_geom = opengl_window.window_geom.clone();
253                    opengl_windows.push(opengl_window);
254                    window.is_created = true;
255                },
256                CxOsOp::CloseWindow(window_id) => {
257                    if let Some(index) = opengl_windows.iter().position( | w | w.window_id == window_id) {
258                        self.windows[window_id].is_created = false;
259                        opengl_windows[index].xlib_window.close_window();
260                        opengl_windows.remove(index);
261                        if opengl_windows.len() == 0 {
262                            ret = EventFlow::Exit
263                        }
264                    }
265                },
266                CxOsOp::Quit=>{
267                    ret = EventFlow::Exit
268                }
269                CxOsOp::MinimizeWindow(window_id) => {
270                    if let Some(window) = opengl_windows.iter_mut().find( | w | w.window_id == window_id) {
271                        window.xlib_window.minimize();
272                    }
273                },
274                CxOsOp::MaximizeWindow(window_id) => {
275                    if let Some(window) = opengl_windows.iter_mut().find( | w | w.window_id == window_id) {
276                        window.xlib_window.maximize();
277                    }
278                },
279                CxOsOp::RestoreWindow(window_id) => {
280                    if let Some(window) = opengl_windows.iter_mut().find( | w | w.window_id == window_id) {
281                        window.xlib_window.restore();
282                    }
283                },
284                CxOsOp::ShowClipboardActions(_) =>{
285                }
286                CxOsOp::FullscreenWindow(_window_id) => {
287                    todo!()
288                },
289                CxOsOp::NormalizeWindow(_window_id) => {
290                    todo!()
291                }
292                CxOsOp::SetTopmost(_window_id, _is_topmost) => {
293                    todo!()
294                }
295                CxOsOp::XrStartPresenting => {
296                    //todo!()
297                },
298                CxOsOp::XrStopPresenting => {
299                    //todo!()
300                },
301                CxOsOp::ShowTextIME(_area, _pos) => {
302                    //todo!()
303                }
304                CxOsOp::HideTextIME => {
305                    //todo!()
306                },
307                CxOsOp::SetCursor(cursor) => {
308                    xlib_app.set_mouse_cursor(cursor);
309                },
310                CxOsOp::StartTimer {timer_id, interval, repeats} => {
311                    xlib_app.start_timer(timer_id, interval, repeats);
312                },
313                CxOsOp::StopTimer(timer_id) => {
314                    xlib_app.stop_timer(timer_id);
315                },
316                CxOsOp::StartDragging(_dragged_item) => {
317                },
318                CxOsOp::UpdateMacosMenu(_menu) => {
319                },
320                CxOsOp::HttpRequest{request_id:_, request:_} => {
321                    todo!()
322                },
323                CxOsOp::WebSocketOpen{request_id:_, request:_}=>{
324                    todo!()
325                }
326                CxOsOp::WebSocketSendBinary{request_id:_, data:_}=>{
327                    todo!()
328                }
329                CxOsOp::WebSocketSendString{request_id:_, data:_}=>{
330                    todo!()
331                },
332                CxOsOp::InitializeVideoDecoding(_, _, _) => todo!(),
333                CxOsOp::DecodeNextVideoChunk(_, _) => todo!(),
334                CxOsOp::FetchNextVideoFrames(_, _) => todo!(),
335                CxOsOp::CleanupVideoDecoding(_) => todo!(),
336            }
337        }
338        ret
339    }
340}
341
342impl CxOsApi for Cx {
343    fn init_cx_os(&mut self) {
344        self.live_expand();
345        self.live_scan_dependencies();
346        self.native_load_dependencies();
347    }
348    
349    fn spawn_thread<F>(&mut self, f: F) where F: FnOnce() + Send + 'static {
350        std::thread::spawn(f);
351    }
352}
353
354#[derive(Default)]
355pub struct CxOs {
356    pub(crate) media: CxLinuxMedia,
357
358    // HACK(eddyb) generalize this to EGL, properly.
359    pub(super) opengl_cx: Option<OpenglCx>,
360}
361