use {
std::cell::RefCell,
std::time::Instant,
std::rc::Rc,
self::super::opengl_x11::{
OpenglWindow,
OpenglCx
},
self::super::super::{
egl_sys,
gl_sys::LibGl,
x11::xlib_event::*,
x11::xlib_app::*,
x11::x11_sys,
linux_media::CxLinuxMedia
},
crate::{
cx_api::{CxOsOp, CxOsApi, OpenUrlInPlace},
makepad_math::dvec2,
makepad_live_id::*,
thread::SignalToUI,
event::*,
pass::CxPassParent,
cx::{Cx, OsType,LinuxWindowParams},
os::cx_stdin::PollTimers,
gpu_info::GpuPerformance,
os::cx_native::EventFlow,
}
};
impl Cx {
pub fn event_loop(cx:Rc<RefCell<Cx>>) {
cx.borrow_mut().self_ref = Some(cx.clone());
cx.borrow_mut().os_type = OsType::LinuxWindow(LinuxWindowParams{
custom_window_chrome: false
});
cx.borrow_mut().gpu_info.performance = GpuPerformance::Tier1;
let opengl_windows = Rc::new(RefCell::new(Vec::new()));
let is_stdin_loop = std::env::args().find(|v| v=="--stdin-loop").is_some();
if is_stdin_loop {
cx.borrow_mut().in_makepad_studio = true;
}
init_xlib_app_global(Box::new({
let cx = cx.clone();
move | xlib_app,
events | {
if is_stdin_loop{
return EventFlow::Wait
}
let mut cx = cx.borrow_mut();
let mut opengl_windows = opengl_windows.borrow_mut();
cx.xlib_event_callback(xlib_app, events, &mut *opengl_windows)
}
}));
cx.borrow_mut().os.opengl_cx = Some(unsafe {
OpenglCx::from_egl_platform_display(
egl_sys::EGL_PLATFORM_X11_EXT,
get_xlib_app_global().display,
)
});
if is_stdin_loop {
cx.borrow_mut().in_makepad_studio = true;
return cx.borrow_mut().stdin_event_loop();
}
cx.borrow_mut().call_event_handler(&Event::Startup);
cx.borrow_mut().redraw_all();
get_xlib_app_global().start_timer(0,0.008,true);
get_xlib_app_global().event_loop();
}
fn xlib_event_callback(
&mut self,
xlib_app: &mut XlibApp,
event: XlibEvent,
opengl_windows: &mut Vec<OpenglWindow>
) -> EventFlow {
if let EventFlow::Exit = self.handle_platform_ops(opengl_windows, xlib_app) {
return EventFlow::Exit
}
match event {
XlibEvent::AppGotFocus => { for window in opengl_windows.iter_mut() {
if let Some(main_pass_id) = self.windows[window.window_id].main_pass_id {
self.repaint_pass(main_pass_id);
}
}
self.call_event_handler(&Event::AppGotFocus);
}
XlibEvent::AppLostFocus => {
self.call_event_handler(&Event::AppLostFocus);
}
XlibEvent::WindowGeomChange(mut re) => { if let Some(window) = opengl_windows.iter_mut().find( | w | w.window_id == re.window_id) {
if let Some(dpi_override) = self.windows[re.window_id].dpi_override {
re.new_geom.inner_size *= re.new_geom.dpi_factor / dpi_override;
re.new_geom.dpi_factor = dpi_override;
}
window.window_geom = re.new_geom.clone();
self.windows[re.window_id].window_geom = re.new_geom.clone();
if re.old_geom.inner_size != re.new_geom.inner_size {
if let Some(main_pass_id) = self.windows[re.window_id].main_pass_id {
self.redraw_pass_and_child_passes(main_pass_id);
}
}
}
self.call_event_handler(&Event::WindowGeomChange(re));
}
XlibEvent::WindowClosed(wc) => {
let window_id = wc.window_id;
self.call_event_handler(&Event::WindowClosed(wc));
self.windows[window_id].is_created = false;
if let Some(index) = opengl_windows.iter().position( | w | w.window_id == window_id) {
opengl_windows.remove(index);
if opengl_windows.len() == 0 {
xlib_app.terminate_event_loop();
self.call_event_handler(&Event::Shutdown);
return EventFlow::Exit
}
}
}
XlibEvent::Paint => {
if self.new_next_frames.len() != 0 {
self.call_next_frame_event(xlib_app.time_now());
}
if self.need_redrawing() {
self.call_draw_event();
self.os.opengl_cx.as_ref().unwrap().make_current();
self.opengl_compile_shaders();
}
self.handle_repaint(opengl_windows);
}
XlibEvent::MouseDown(e) => {
self.fingers.process_tap_count(
e.abs,
e.time
);
self.fingers.mouse_down(e.button, e.window_id);
self.call_event_handler(&Event::MouseDown(e.into()))
}
XlibEvent::MouseMove(e) => {
self.call_event_handler(&Event::MouseMove(e.into()));
self.fingers.cycle_hover_area(live_id!(mouse).into());
self.fingers.switch_captures();
}
XlibEvent::MouseUp(e) => {
let button = e.button;
self.call_event_handler(&Event::MouseUp(e.into()));
self.fingers.mouse_up(button);
self.fingers.cycle_hover_area(live_id!(mouse).into());
}
XlibEvent::Scroll(e) => {
self.call_event_handler(&Event::Scroll(e.into()))
}
XlibEvent::WindowDragQuery(e) => {
self.call_event_handler(&Event::WindowDragQuery(e))
}
XlibEvent::WindowCloseRequested(e) => {
self.call_event_handler(&Event::WindowCloseRequested(e))
}
XlibEvent::TextInput(e) => {
self.call_event_handler(&Event::TextInput(e))
}
XlibEvent::Drag(e) => {
self.call_event_handler(&Event::Drag(e))
}
XlibEvent::Drop(e) => {
self.call_event_handler(&Event::Drop(e))
}
XlibEvent::DragEnd => {
self.call_event_handler(&Event::DragEnd)
}
XlibEvent::KeyDown(e) => {
self.keyboard.process_key_down(e.clone());
self.call_event_handler(&Event::KeyDown(e))
}
XlibEvent::KeyUp(e) => {
self.keyboard.process_key_up(e.clone());
self.call_event_handler(&Event::KeyUp(e))
}
XlibEvent::TextCopy(e) => {
self.call_event_handler(&Event::TextCopy(e))
}
XlibEvent::TextCut(e) => {
self.call_event_handler(&Event::TextCut(e))
}
XlibEvent::Timer(e) => {
if e.timer_id == 0{
if SignalToUI::check_and_clear_ui_signal(){
self.handle_media_signals();
self.call_event_handler(&Event::Signal);
}
self.handle_action_receiver();
}
else{
self.call_event_handler(&Event::Timer(e))
}
if self.handle_live_edit() {
self.call_event_handler(&Event::LiveEdit);
self.redraw_all();
}
return EventFlow::Wait;
}
}
EventFlow::Poll
}
pub(crate) fn handle_networking_events(&mut self) {
}
pub (crate) fn handle_repaint(&mut self, opengl_windows: &mut Vec<OpenglWindow>) {
self.os.opengl_cx.as_ref().unwrap().make_current();
let mut passes_todo = Vec::new();
self.compute_pass_repaint_order(&mut passes_todo);
self.repaint_id += 1;
for pass_id in &passes_todo {
self.passes[*pass_id].set_time(get_xlib_app_global().time_now() as f32);
match self.passes[*pass_id].parent.clone() {
CxPassParent::Xr => {}
CxPassParent::Window(window_id) => {
if let Some(window) = opengl_windows.iter_mut().find( | w | w.window_id == window_id) {
window.resize_buffers();
self.draw_pass_to_window(*pass_id, window);
}
}
CxPassParent::Pass(_) => {
self.draw_pass_to_texture(*pass_id, None);
},
CxPassParent::None => {
self.draw_pass_to_texture(*pass_id, None);
}
}
}
}
fn handle_platform_ops(&mut self, opengl_windows: &mut Vec<OpenglWindow>, xlib_app: &mut XlibApp) -> EventFlow {
let mut ret = EventFlow::Poll;
while let Some(op) = self.platform_ops.pop() {
match op {
CxOsOp::CreateWindow(window_id) => {
let window = &mut self.windows[window_id];
let opengl_window = OpenglWindow::new(
window_id,
self.os.opengl_cx.as_ref().unwrap(),
window.create_inner_size.unwrap_or(dvec2(800., 600.)),
window.create_position,
&window.create_title,
);
window.window_geom = opengl_window.window_geom.clone();
opengl_windows.push(opengl_window);
window.is_created = true;
},
CxOsOp::CloseWindow(window_id) => {
self.call_event_handler(&Event::WindowClosed(WindowClosedEvent { window_id }));
if let Some(index) = opengl_windows.iter().position( | w | w.window_id == window_id) {
self.windows[window_id].is_created = false;
opengl_windows[index].xlib_window.close_window();
opengl_windows.remove(index);
if opengl_windows.len() == 0 {
ret = EventFlow::Exit
}
}
},
CxOsOp::Quit=>{
ret = EventFlow::Exit
}
CxOsOp::MinimizeWindow(window_id) => {
if let Some(window) = opengl_windows.iter_mut().find( | w | w.window_id == window_id) {
window.xlib_window.minimize();
}
},
CxOsOp::Deminiaturize(_window_id) => todo!(),
CxOsOp::HideWindow(_window_id) => todo!(),
CxOsOp::MaximizeWindow(window_id) => {
if let Some(window) = opengl_windows.iter_mut().find( | w | w.window_id == window_id) {
window.xlib_window.maximize();
}
},
CxOsOp::RestoreWindow(window_id) => {
if let Some(window) = opengl_windows.iter_mut().find( | w | w.window_id == window_id) {
window.xlib_window.restore();
}
},
CxOsOp::ResizeWindow(window_id, size) => {
if let Some(window) = opengl_windows.iter_mut().find( | w | w.window_id == window_id) {
window.xlib_window.set_inner_size(size);
}
},
CxOsOp::RepositionWindow(window_id, size) => {
if let Some(window) = opengl_windows.iter_mut().find( | w | w.window_id == window_id) {
window.xlib_window.set_position(size);
}
},
CxOsOp::ShowClipboardActions(_) =>{
},
CxOsOp::CopyToClipboard(content) => {
if let Some(window) = opengl_windows.get(0) {
unsafe {
xlib_app.copy_to_clipboard(&content, window.xlib_window.window.unwrap(), x11_sys::CurrentTime as u64)
}
}
}
CxOsOp::SetCursor(cursor) => {
xlib_app.set_mouse_cursor(cursor);
},
CxOsOp::StartTimer {timer_id, interval, repeats} => {
xlib_app.start_timer(timer_id, interval, repeats);
},
CxOsOp::StopTimer(timer_id) => {
xlib_app.stop_timer(timer_id);
},
CxOsOp::ShowTextIME(area, pos) => {
let pos = area.clipped_rect(self).pos + pos;
opengl_windows.iter_mut().for_each(|w| {
w.xlib_window.set_ime_spot(pos);
});
},
CxOsOp::HideTextIME => {
opengl_windows.iter_mut().for_each(|w| {
w.xlib_window.set_ime_spot(dvec2(0.0,0.0));
});
},
e=>{
crate::error!("Not implemented on this platform: CxOsOp::{:?}", e);
}
}
}
ret
}
}
impl CxOsApi for Cx {
fn init_cx_os(&mut self) {
self.os.start_time = Some(Instant::now());
if let Some(item) = std::option_env!("MAKEPAD_PACKAGE_DIR"){
self.live_registry.borrow_mut().package_root = Some(item.to_string());
}
self.live_expand();
if !Self::has_studio_web_socket() {
self.start_disk_live_file_watcher(100);
}
self.live_scan_dependencies();
self.native_load_dependencies();
}
fn spawn_thread<F>(&mut self, f: F) where F: FnOnce() + Send + 'static {
std::thread::spawn(f);
}
fn seconds_since_app_start(&self)->f64{
Instant::now().duration_since(self.os.start_time.unwrap()).as_secs_f64()
}
fn open_url(&mut self, _url:&str, _in_place:OpenUrlInPlace){
crate::error!("open_url not implemented on this platform");
}
}
#[derive(Default)]
pub struct CxOs {
pub(crate) media: CxLinuxMedia,
pub (crate) stdin_timers: PollTimers,
pub (crate) start_time: Option<Instant>,
pub(super) opengl_cx: Option<OpenglCx>,
}
impl CxOs{
pub(crate) fn gl(&self)->&LibGl{
&self.opengl_cx.as_ref().unwrap().libgl
}
}