makepad_platform/os/linux/x11/
linux_x11.rs1use {
2 std::cell::RefCell,
3 std::time::Instant,
4 std::rc::Rc,
5 self::super::opengl_x11::{
6 OpenglWindow,
7 OpenglCx
8 },
9 self::super::super::{
10 egl_sys,
11 gl_sys::LibGl,
12 x11::xlib_event::*,
13 x11::xlib_app::*,
14 x11::x11_sys,
15 linux_media::CxLinuxMedia
16 },
17 crate::{
18 cx_api::{CxOsOp, CxOsApi, OpenUrlInPlace},
19 makepad_math::dvec2,
20 makepad_live_id::*,
21 thread::SignalToUI,
22 event::*,
23 pass::CxPassParent,
24 cx::{Cx, OsType,LinuxWindowParams},
25 os::cx_stdin::PollTimers,
26 gpu_info::GpuPerformance,
27 os::cx_native::EventFlow,
28 }
29};
30
31impl Cx {
32 pub fn event_loop(cx:Rc<RefCell<Cx>>) {
33 cx.borrow_mut().self_ref = Some(cx.clone());
34 cx.borrow_mut().os_type = OsType::LinuxWindow(LinuxWindowParams{
35 custom_window_chrome: false
36 });
37 cx.borrow_mut().gpu_info.performance = GpuPerformance::Tier1;
38
39 let opengl_windows = Rc::new(RefCell::new(Vec::new()));
40 let is_stdin_loop = std::env::args().find(|v| v=="--stdin-loop").is_some();
41 if is_stdin_loop {
42 cx.borrow_mut().in_makepad_studio = true;
43 }
44 init_xlib_app_global(Box::new({
45 let cx = cx.clone();
46 move | xlib_app,
47 events | {
48 if is_stdin_loop{
49 return EventFlow::Wait
50 }
51 let mut cx = cx.borrow_mut();
52 let mut opengl_windows = opengl_windows.borrow_mut();
53 cx.xlib_event_callback(xlib_app, events, &mut *opengl_windows)
54 }
55 }));
56
57 cx.borrow_mut().os.opengl_cx = Some(unsafe {
58 OpenglCx::from_egl_platform_display(
59 egl_sys::EGL_PLATFORM_X11_EXT,
60 get_xlib_app_global().display,
61 )
62 });
63
64 if is_stdin_loop {
65 cx.borrow_mut().in_makepad_studio = true;
66 return cx.borrow_mut().stdin_event_loop();
67 }
68
69 cx.borrow_mut().call_event_handler(&Event::Startup);
70 cx.borrow_mut().redraw_all();
71 get_xlib_app_global().start_timer(0,0.008,true);
72 get_xlib_app_global().event_loop();
73 }
74
75 fn xlib_event_callback(
76 &mut self,
77 xlib_app: &mut XlibApp,
78 event: XlibEvent,
79 opengl_windows: &mut Vec<OpenglWindow>
80 ) -> EventFlow {
81 if let EventFlow::Exit = self.handle_platform_ops(opengl_windows, xlib_app) {
82 return EventFlow::Exit
83 }
84
85 match event {
89 XlibEvent::AppGotFocus => { for window in opengl_windows.iter_mut() {
91 if let Some(main_pass_id) = self.windows[window.window_id].main_pass_id {
92 self.repaint_pass(main_pass_id);
93 }
94 }
95 self.call_event_handler(&Event::AppGotFocus);
97 }
98 XlibEvent::AppLostFocus => {
99 self.call_event_handler(&Event::AppLostFocus);
100 }
101 XlibEvent::WindowGeomChange(mut re) => { if let Some(window) = opengl_windows.iter_mut().find( | w | w.window_id == re.window_id) {
103 if let Some(dpi_override) = self.windows[re.window_id].dpi_override {
104 re.new_geom.inner_size *= re.new_geom.dpi_factor / dpi_override;
105 re.new_geom.dpi_factor = dpi_override;
106 }
107
108 window.window_geom = re.new_geom.clone();
109 self.windows[re.window_id].window_geom = re.new_geom.clone();
110 if re.old_geom.inner_size != re.new_geom.inner_size {
112 if let Some(main_pass_id) = self.windows[re.window_id].main_pass_id {
113 self.redraw_pass_and_child_passes(main_pass_id);
114 }
115 }
116 }
117 self.call_event_handler(&Event::WindowGeomChange(re));
119 }
120 XlibEvent::WindowClosed(wc) => {
121 let window_id = wc.window_id;
122 self.call_event_handler(&Event::WindowClosed(wc));
123 self.windows[window_id].is_created = false;
125 if let Some(index) = opengl_windows.iter().position( | w | w.window_id == window_id) {
126 opengl_windows.remove(index);
127 if opengl_windows.len() == 0 {
128 xlib_app.terminate_event_loop();
129 self.call_event_handler(&Event::Shutdown);
130 return EventFlow::Exit
131 }
132 }
133 }
134 XlibEvent::Paint => {
135 if self.new_next_frames.len() != 0 {
136 self.call_next_frame_event(xlib_app.time_now());
137 }
138 if self.need_redrawing() {
139 self.call_draw_event();
140 self.os.opengl_cx.as_ref().unwrap().make_current();
141 self.opengl_compile_shaders();
142 }
143 self.handle_repaint(opengl_windows);
146 }
147 XlibEvent::MouseDown(e) => {
148 self.fingers.process_tap_count(
149 e.abs,
150 e.time
151 );
152 self.fingers.mouse_down(e.button, e.window_id);
153 self.call_event_handler(&Event::MouseDown(e.into()))
154 }
155 XlibEvent::MouseMove(e) => {
156 self.call_event_handler(&Event::MouseMove(e.into()));
157 self.fingers.cycle_hover_area(live_id!(mouse).into());
158 self.fingers.switch_captures();
159 }
160 XlibEvent::MouseUp(e) => {
161 let button = e.button;
162 self.call_event_handler(&Event::MouseUp(e.into()));
163 self.fingers.mouse_up(button);
164 self.fingers.cycle_hover_area(live_id!(mouse).into());
165 }
166 XlibEvent::Scroll(e) => {
167 self.call_event_handler(&Event::Scroll(e.into()))
168 }
169 XlibEvent::WindowDragQuery(e) => {
170 self.call_event_handler(&Event::WindowDragQuery(e))
171 }
172 XlibEvent::WindowCloseRequested(e) => {
173 self.call_event_handler(&Event::WindowCloseRequested(e))
174 }
175 XlibEvent::TextInput(e) => {
176 self.call_event_handler(&Event::TextInput(e))
177 }
178 XlibEvent::Drag(e) => {
179 self.call_event_handler(&Event::Drag(e))
180 }
181 XlibEvent::Drop(e) => {
182 self.call_event_handler(&Event::Drop(e))
183 }
184 XlibEvent::DragEnd => {
185 self.call_event_handler(&Event::DragEnd)
186 }
187 XlibEvent::KeyDown(e) => {
188 self.keyboard.process_key_down(e.clone());
189 self.call_event_handler(&Event::KeyDown(e))
190 }
191 XlibEvent::KeyUp(e) => {
192 self.keyboard.process_key_up(e.clone());
193 self.call_event_handler(&Event::KeyUp(e))
194 }
195 XlibEvent::TextCopy(e) => {
196 self.call_event_handler(&Event::TextCopy(e))
197 }
198 XlibEvent::TextCut(e) => {
199 self.call_event_handler(&Event::TextCut(e))
200 }
201 XlibEvent::Timer(e) => {
202 if e.timer_id == 0{
204 if SignalToUI::check_and_clear_ui_signal(){
205 self.handle_media_signals();
206 self.call_event_handler(&Event::Signal);
207 }
208 self.handle_action_receiver();
209 }
210 else{
211 self.call_event_handler(&Event::Timer(e))
212 }
213
214 if self.handle_live_edit() {
215 self.call_event_handler(&Event::LiveEdit);
216 self.redraw_all();
217 }
218 return EventFlow::Wait;
219 }
220 }
221
222 EventFlow::Poll
224 }
229
230 pub(crate) fn handle_networking_events(&mut self) {
231 }
232
233 pub (crate) fn handle_repaint(&mut self, opengl_windows: &mut Vec<OpenglWindow>) {
234 self.os.opengl_cx.as_ref().unwrap().make_current();
235 let mut passes_todo = Vec::new();
236 self.compute_pass_repaint_order(&mut passes_todo);
237 self.repaint_id += 1;
238 for pass_id in &passes_todo {
239 self.passes[*pass_id].set_time(get_xlib_app_global().time_now() as f32);
240 match self.passes[*pass_id].parent.clone() {
241 CxPassParent::Xr => {}
242 CxPassParent::Window(window_id) => {
243 if let Some(window) = opengl_windows.iter_mut().find( | w | w.window_id == window_id) {
244 window.resize_buffers();
246 self.draw_pass_to_window(*pass_id, window);
247 }
248 }
249 CxPassParent::Pass(_) => {
250 self.draw_pass_to_texture(*pass_id, None);
252 },
253 CxPassParent::None => {
254 self.draw_pass_to_texture(*pass_id, None);
255 }
256 }
257 }
258 }
259
260 fn handle_platform_ops(&mut self, opengl_windows: &mut Vec<OpenglWindow>, xlib_app: &mut XlibApp) -> EventFlow {
261 let mut ret = EventFlow::Poll;
262 while let Some(op) = self.platform_ops.pop() {
263 match op {
264 CxOsOp::CreateWindow(window_id) => {
265 let window = &mut self.windows[window_id];
266 let opengl_window = OpenglWindow::new(
267 window_id,
268 self.os.opengl_cx.as_ref().unwrap(),
269 window.create_inner_size.unwrap_or(dvec2(800., 600.)),
270 window.create_position,
271 &window.create_title,
272 );
273 window.window_geom = opengl_window.window_geom.clone();
274 opengl_windows.push(opengl_window);
275 window.is_created = true;
276 },
277 CxOsOp::CloseWindow(window_id) => {
278 self.call_event_handler(&Event::WindowClosed(WindowClosedEvent { window_id }));
279 if let Some(index) = opengl_windows.iter().position( | w | w.window_id == window_id) {
280 self.windows[window_id].is_created = false;
281 opengl_windows[index].xlib_window.close_window();
282 opengl_windows.remove(index);
283 if opengl_windows.len() == 0 {
284 ret = EventFlow::Exit
285 }
286 }
287 },
288 CxOsOp::Quit=>{
289 ret = EventFlow::Exit
290 }
291 CxOsOp::MinimizeWindow(window_id) => {
292 if let Some(window) = opengl_windows.iter_mut().find( | w | w.window_id == window_id) {
293 window.xlib_window.minimize();
294 }
295 },
296 CxOsOp::Deminiaturize(_window_id) => todo!(),
297 CxOsOp::HideWindow(_window_id) => todo!(),
298 CxOsOp::MaximizeWindow(window_id) => {
299 if let Some(window) = opengl_windows.iter_mut().find( | w | w.window_id == window_id) {
300 window.xlib_window.maximize();
301 }
302 },
303 CxOsOp::RestoreWindow(window_id) => {
304 if let Some(window) = opengl_windows.iter_mut().find( | w | w.window_id == window_id) {
305 window.xlib_window.restore();
306 }
307 },
308 CxOsOp::ResizeWindow(window_id, size) => {
309 if let Some(window) = opengl_windows.iter_mut().find( | w | w.window_id == window_id) {
310 window.xlib_window.set_inner_size(size);
311 }
312 },
313 CxOsOp::RepositionWindow(window_id, size) => {
314 if let Some(window) = opengl_windows.iter_mut().find( | w | w.window_id == window_id) {
315 window.xlib_window.set_position(size);
316 }
317 },
318 CxOsOp::ShowClipboardActions(_) =>{
319 },
320 CxOsOp::CopyToClipboard(content) => {
321 if let Some(window) = opengl_windows.get(0) {
322 unsafe {
323 xlib_app.copy_to_clipboard(&content, window.xlib_window.window.unwrap(), x11_sys::CurrentTime as u64)
324 }
325 }
326 }
327 CxOsOp::SetCursor(cursor) => {
328 xlib_app.set_mouse_cursor(cursor);
329 },
330 CxOsOp::StartTimer {timer_id, interval, repeats} => {
331 xlib_app.start_timer(timer_id, interval, repeats);
332 },
333 CxOsOp::StopTimer(timer_id) => {
334 xlib_app.stop_timer(timer_id);
335 },
336 CxOsOp::ShowTextIME(area, pos) => {
337 let pos = area.clipped_rect(self).pos + pos;
338 opengl_windows.iter_mut().for_each(|w| {
339 w.xlib_window.set_ime_spot(pos);
340 });
341 },
342 CxOsOp::HideTextIME => {
343 opengl_windows.iter_mut().for_each(|w| {
344 w.xlib_window.set_ime_spot(dvec2(0.0,0.0));
345 });
346 },
347 e=>{
348 crate::error!("Not implemented on this platform: CxOsOp::{:?}", e);
349 }
350 }
351 }
352 ret
353 }
354}
355
356impl CxOsApi for Cx {
357 fn init_cx_os(&mut self) {
358 self.os.start_time = Some(Instant::now());
359 if let Some(item) = std::option_env!("MAKEPAD_PACKAGE_DIR"){
360 self.live_registry.borrow_mut().package_root = Some(item.to_string());
361 }
362 self.live_expand();
363 if !Self::has_studio_web_socket() {
364 self.start_disk_live_file_watcher(100);
365 }
366 self.live_scan_dependencies();
367 self.native_load_dependencies();
368 }
369
370 fn spawn_thread<F>(&mut self, f: F) where F: FnOnce() + Send + 'static {
371 std::thread::spawn(f);
372 }
373
374 fn seconds_since_app_start(&self)->f64{
375 Instant::now().duration_since(self.os.start_time.unwrap()).as_secs_f64()
376 }
377
378 fn open_url(&mut self, _url:&str, _in_place:OpenUrlInPlace){
379 crate::error!("open_url not implemented on this platform");
380 }
381}
382
383#[derive(Default)]
384pub struct CxOs {
385 pub(crate) media: CxLinuxMedia,
386 pub (crate) stdin_timers: PollTimers,
387 pub (crate) start_time: Option<Instant>,
388 pub(super) opengl_cx: Option<OpenglCx>,
390}
391
392impl CxOs{
393 pub(crate) fn gl(&self)->&LibGl{
394 &self.opengl_cx.as_ref().unwrap().libgl
395 }
396}