pub fn open_session_log_popout( app: >k::Application, handle: &Rc>>, buffer: >k::TextBuffer, ) { open_text_buffer_popout( app, handle, None, buffer, "Lesavka Log", "Copy", gtk::WrapMode::WordChar, ); } pub fn open_diagnostics_popout( app: >k::Application, handle: &Rc>>, label_handle: &Rc>>, scroll_handle: &Rc>>, rendered_text: &Rc>, ) { if let Some(window) = handle.borrow().as_ref() { window.present(); return; } let window = gtk::ApplicationWindow::builder() .application(app) .title("Lesavka Diagnostics") .default_width(980) .default_height(680) .build(); super::ui_components::install_css(&window); super::ui_components::install_window_icon(&window); super::ui_components::install_window_chrome(&window, "Lesavka Diagnostics"); let root = gtk::Box::new(gtk::Orientation::Vertical, 10); root.set_margin_start(14); root.set_margin_end(14); root.set_margin_top(14); root.set_margin_bottom(14); let toolbar = gtk::Box::new(gtk::Orientation::Horizontal, 8); let copy_button = gtk::Button::with_label("Copy Report"); toolbar.append(©_button); root.append(&toolbar); let current_text = rendered_text.borrow().clone(); let label = gtk::Label::new(Some(¤t_text)); label.add_css_class("status-log"); label.set_selectable(true); label.set_xalign(0.0); label.set_yalign(0.0); label.set_wrap(false); label.set_halign(gtk::Align::Start); label.set_valign(gtk::Align::Start); label.set_hexpand(true); let shell = gtk::Box::new(gtk::Orientation::Vertical, 0); shell.set_hexpand(true); shell.set_vexpand(false); shell.append(&label); let scroll = gtk::ScrolledWindow::builder() .hexpand(true) .vexpand(true) .child(&shell) .build(); *label_handle.borrow_mut() = Some(label.clone()); *scroll_handle.borrow_mut() = Some(scroll.clone()); root.append(&scroll); window.set_child(Some(&root)); window.maximize(); { let rendered_text = Rc::clone(rendered_text); copy_button.connect_clicked(move |_| { let current_text = rendered_text.borrow().clone(); let _ = copy_plain_text(¤t_text); }); } { let handle = Rc::clone(handle); let label_handle = Rc::clone(label_handle); let scroll_handle = Rc::clone(scroll_handle); window.connect_close_request(move |_| { handle.borrow_mut().take(); label_handle.borrow_mut().take(); scroll_handle.borrow_mut().take(); glib::Propagation::Proceed }); } *handle.borrow_mut() = Some(window.clone()); window.present(); } fn open_text_buffer_popout( app: >k::Application, handle: &Rc>>, scroll_handle: Option<&Rc>>>, buffer: >k::TextBuffer, title: &str, copy_button_label: &str, wrap_mode: gtk::WrapMode, ) { if let Some(window) = handle.borrow().as_ref() { window.present(); return; } let window = gtk::ApplicationWindow::builder() .application(app) .title(title) .default_width(980) .default_height(680) .build(); super::ui_components::install_css(&window); super::ui_components::install_window_icon(&window); super::ui_components::install_window_chrome(&window, title); let root = gtk::Box::new(gtk::Orientation::Vertical, 10); root.set_margin_start(14); root.set_margin_end(14); root.set_margin_top(14); root.set_margin_bottom(14); let toolbar = gtk::Box::new(gtk::Orientation::Horizontal, 8); let copy_button = gtk::Button::with_label(copy_button_label); toolbar.append(©_button); root.append(&toolbar); let view = gtk::TextView::with_buffer(buffer); view.add_css_class("status-log"); view.set_editable(false); view.set_cursor_visible(false); view.set_monospace(true); view.set_wrap_mode(wrap_mode); let scroll = gtk::ScrolledWindow::builder() .hexpand(true) .vexpand(true) .child(&view) .build(); if let Some(scroll_handle) = scroll_handle { *scroll_handle.borrow_mut() = Some(scroll.clone()); } root.append(&scroll); window.set_child(Some(&root)); window.maximize(); { let buffer = buffer.clone(); copy_button.connect_clicked(move |_| { let _ = copy_session_log(&buffer); }); } { let handle = Rc::clone(handle); let scroll_handle = scroll_handle.cloned(); window.connect_close_request(move |_| { handle.borrow_mut().take(); if let Some(scroll_handle) = &scroll_handle { scroll_handle.borrow_mut().take(); } glib::Propagation::Proceed }); } *handle.borrow_mut() = Some(window.clone()); window.present(); } pub fn stop_child_process(child_proc: &Rc>>) { if let Some(mut child) = child_proc.borrow_mut().take() { let _ = child.kill(); let _ = child.wait(); } } pub fn shutdown_launcher_runtime( child_proc: &Rc>>, tests: &Rc>, preview: Option<&LauncherPreview>, widgets: &LauncherWidgets, popouts: &Rc; 2]>>, diagnostics_popout: &Rc>>, log_popout: &Rc>>, ) { stop_child_process(child_proc); tests.borrow_mut().stop_all(); if let Some(preview) = preview { preview.set_session_active(false); preview.shutdown_all(); } for pane in &widgets.display_panes { if let Some(binding) = pane.preview_binding.borrow_mut().take() { binding.close(); } pane.picture.set_paintable(Option::<&gdk::Paintable>::None); pane.stream_status.set_text(""); } let mut detached_popouts = Vec::new(); { let mut slots = popouts.borrow_mut(); for slot in slots.iter_mut() { if let Some(handle) = slot.take() { detached_popouts.push(handle); } } } for handle in detached_popouts { handle.binding.close(); handle .picture .set_paintable(Option::<&gdk::Paintable>::None); handle.window.set_child(Option::<>k::Widget>::None); handle.window.hide(); } if let Some(window) = diagnostics_popout.borrow_mut().take() { widgets.diagnostics_popout_label.borrow_mut().take(); widgets.diagnostics_popout_scroll.borrow_mut().take(); window.set_child(Option::<>k::Widget>::None); window.hide(); } if let Some(window) = log_popout.borrow_mut().take() { window.set_child(Option::<>k::Widget>::None); window.hide(); } } pub fn reap_exited_child(child_proc: &Rc>>) -> bool { let mut slot = child_proc.borrow_mut(); match slot.as_mut() { Some(child) => match child.try_wait() { Ok(Some(_)) => { *slot = None; false } Ok(None) | Err(_) => true, }, None => false, } } pub fn next_input_routing(routing: InputRouting) -> InputRouting { match routing { InputRouting::Remote => InputRouting::Local, InputRouting::Local => InputRouting::Remote, } }