diff --git a/Cargo.lock b/Cargo.lock index a4c19f5..ef952a2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,18 @@ dependencies = [ "memchr", ] +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + [[package]] name = "autocfg" version = "1.3.0" @@ -114,6 +126,21 @@ dependencies = [ "libloading", ] +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + [[package]] name = "duct" version = "0.13.7" @@ -132,10 +159,32 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener", + "pin-project-lite", +] + [[package]] name = "fedora-kernel-manager" version = "0.1.0" dependencies = [ + "async-channel", "duct", "glib", "glib-build-tools", @@ -655,6 +704,12 @@ dependencies = [ "system-deps", ] +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + [[package]] name = "peeking_take_while" version = "0.1.2" diff --git a/Cargo.toml b/Cargo.toml index ccc470c..eff96f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,6 +8,7 @@ edition = "2021" [dependencies] adw = { version = "0.6.0", package = "libadwaita", features = ["v1_5"] } +async-channel = "2.3.1" duct = "0.13.7" glib = "0.19.7" gtk = { version = "0.8.2", package = "gtk4", features = ["v4_14"] } diff --git a/src/build_ui/mod.rs b/src/build_ui/mod.rs index 11abe0a..c0e8fc8 100644 --- a/src/build_ui/mod.rs +++ b/src/build_ui/mod.rs @@ -1,21 +1,56 @@ -use crate::{content, sched_ext, PRETTY_NAME}; +use crate::{content, kernel_pkg, sched_ext, KernelBranch, PRETTY_NAME}; use adw::prelude::*; use adw::*; +use async_channel::*; +use glib::{clone, MainContext}; use gtk::prelude::*; use gtk::*; +use std::cell::RefCell; +use std::process::Command; +use std::rc::Rc; +use std::{thread, time}; pub fn build_ui(app: &adw::Application) { - let window = adw::ApplicationWindow::new(app); + let internet_connected = Rc::new(RefCell::new(false)); + let selected_kernel_branch: Rc>; - load_icon_theme(&window); + let (internet_loop_sender, internet_loop_receiver) = async_channel::unbounded(); + let internet_loop_sender = internet_loop_sender.clone(); - window.connect_close_request(move |window| { - if let Some(application) = window.application() { - application.remove_window(window); - } - glib::Propagation::Proceed + std::thread::spawn(move || loop { + match Command::new("ping").arg("google.com").arg("-c 1").output() { + Ok(t) if t.status.success() => internet_loop_sender + .send_blocking(true) + .expect("The channel needs to be open"), + _ => internet_loop_sender + .send_blocking(false) + .expect("The channel needs to be open"), + }; + thread::sleep(time::Duration::from_secs(5)); }); + let window_banner = adw::Banner::builder().revealed(false).build(); + + let internet_connected_status = internet_connected.clone(); + + let internet_loop_context = MainContext::default(); + // The main loop executes the asynchronous block + internet_loop_context.spawn_local(clone!(@weak window_banner => async move { + while let Ok(state) = internet_loop_receiver.recv().await { + let banner_text = "Warning: No internet connection"; + if state == true { + *internet_connected_status.borrow_mut()=true; + if window_banner.title() == banner_text { + window_banner.set_revealed(false) + } + } else { + *internet_connected_status.borrow_mut()=false; + window_banner.set_title(banner_text); + window_banner.set_revealed(true) + } + } + })); + let window_headerbar = adw::HeaderBar::builder() .title_widget(&adw::WindowTitle::builder().title(PRETTY_NAME).build()) .build(); @@ -31,8 +66,13 @@ pub fn build_ui(app: &adw::Application) { &sched_ext::sched_ext_page(&content_stack), Some("sched_ext_page"), ); + content_stack.add_named( + &kernel_pkg::kernel_pkg_page(&content_stack), + Some("kernel_pkg_page"), + ); window_toolbar.add_top_bar(&window_headerbar); + window_toolbar.add_top_bar(&window_banner); let window = adw::ApplicationWindow::builder() .application(app) @@ -42,6 +82,15 @@ pub fn build_ui(app: &adw::Application) { .resizable(false) .build(); + load_icon_theme(&window); + + window.connect_close_request(move |window| { + if let Some(application) = window.application() { + application.remove_window(window); + } + glib::Propagation::Proceed + }); + window.present(); } diff --git a/src/content/mod.rs b/src/content/mod.rs index 9aebda8..066ef88 100644 --- a/src/content/mod.rs +++ b/src/content/mod.rs @@ -79,6 +79,10 @@ pub fn content(content_stack: >k::Stack) -> gtk::Box { .build(); browse_kernels_button.add_css_class("circular"); + browse_kernels_button.connect_clicked(clone!(@weak content_stack => move |_| { + content_stack.set_visible_child_name("kernel_pkg_page") + })); + let config_kernel_button = gtk::Button::builder() .icon_name("settings") .halign(Align::End) diff --git a/src/kernel_pkg/mod.rs b/src/kernel_pkg/mod.rs new file mode 100644 index 0000000..8bd065e --- /dev/null +++ b/src/kernel_pkg/mod.rs @@ -0,0 +1,216 @@ +use crate::content::get_running_kernel_info; +use crate::RunningKernelInfo; +use adw::prelude::*; +use glib::*; +use gtk::prelude::*; +use gtk::*; +use std::fs; +use std::fs::*; + +pub fn kernel_pkg_page(content_stack: >k::Stack) -> gtk::Box { + let main_box = gtk::Box::builder() + .hexpand(true) + .vexpand(true) + .orientation(Orientation::Vertical) + .build(); + + let kernel_badges_size_group = gtk::SizeGroup::new(SizeGroupMode::Both); + let kernel_badges_size_group0 = gtk::SizeGroup::new(SizeGroupMode::Both); + let kernel_badges_size_group1 = gtk::SizeGroup::new(SizeGroupMode::Both); + + let main_icon = gtk::Image::builder() + .pixel_size(128) + .halign(Align::Center) + .hexpand(true) + .margin_start(10) + .margin_end(10) + .margin_bottom(20) + .margin_top(20) + .build(); + + main_icon.set_icon_name(Some("tux-symbolic")); + + main_icon.add_css_class("symbolic-accent-bg"); + + let main_label = gtk::Label::builder() + .label("Sched-EXT Configuration Settings") + .hexpand(true) + .margin_start(10) + .margin_end(10) + .margin_bottom(20) + .margin_top(20) + .build(); + main_label.add_css_class("symbolic-accent-bg"); + + let badge_box = gtk::Box::builder() + .hexpand(true) + .valign(Align::Start) + .orientation(Orientation::Vertical) + .build(); + + create_current_sched_badge( + &badge_box, + &get_running_kernel_info(), + &kernel_badges_size_group, + &kernel_badges_size_group0, + &kernel_badges_size_group1, + ); + + let scx_sched_expander_row = adw::ExpanderRow::builder() + .subtitle("Select Sched-EXT Scheduler") + .build(); + + scx_sched_expander_row.add_row(&scx_sched_expandable(&scx_sched_expander_row)); + + let scx_sched_expander_row_boxedlist = gtk::ListBox::builder() + .selection_mode(SelectionMode::None) + .hexpand(true) + .vexpand(true) + .valign(Align::Start) + .halign(Align::Center) + .margin_start(10) + .margin_end(10) + .margin_bottom(20) + .margin_top(20) + .build(); + + scx_sched_expander_row_boxedlist.add_css_class("boxed-list"); + scx_sched_expander_row_boxedlist.append(&scx_sched_expander_row); + + let window_bottombar = gtk::Box::builder() + .hexpand(true) + .homogeneous(true) + .margin_bottom(15) + .margin_start(15) + .margin_end(15) + .margin_start(15) + .build(); + + let back_button = gtk::Button::builder() + .halign(Align::Start) + .label("Back") + .build(); + + back_button.add_css_class("pill"); + + back_button.connect_clicked(clone!(@weak content_stack => move |_| { + content_stack.set_visible_child_name("content_page") + })); + + window_bottombar.append(&back_button); + + main_box.append(&badge_box); + main_box.append(&scx_sched_expander_row_boxedlist); + main_box.append(&main_icon); + main_box.append(&main_label); + main_box.append(&window_bottombar); + + main_box +} + +fn create_current_sched_badge( + badge_box: >k::Box, + running_kernel_info: &RunningKernelInfo, + kernel_badges_size_group: >k::SizeGroup, + kernel_badges_size_group0: >k::SizeGroup, + kernel_badges_size_group1: >k::SizeGroup, +) { + while let Some(widget) = badge_box.last_child() { + badge_box.remove(&widget); + } + + badge_box.append(&crate::content::create_kernel_badge( + "Running Sched", + &running_kernel_info.sched, + "background-accent-bg", + &kernel_badges_size_group, + &kernel_badges_size_group0, + &kernel_badges_size_group1, + )); +} + +fn scx_sched_expandable(expander_row: &adw::ExpanderRow) -> gtk::ListBox { + let searchbar = gtk::SearchEntry::builder().search_delay(500).build(); + searchbar.add_css_class("round-border-only-top"); + + let boxedlist = gtk::ListBox::builder() + .selection_mode(SelectionMode::None) + .build(); + + boxedlist.append(&searchbar); + + let sched_container = gtk::ListBox::builder() + .selection_mode(SelectionMode::None) + .build(); + sched_container.add_css_class("boxed-list"); + + let null_checkbutton = gtk::CheckButton::builder() + .label("No branch selected") + .build(); + + let mut scx_sched_array: Vec = Vec::new(); + let data = fs::read_to_string( + "/home/ward/RustroverProjects/fedora-kernel-manager/data/scx_scheds.json", + ) + .expect("Unable to read file"); + let res: serde_json::Value = serde_json::from_str(&data).expect("Unable to parse"); + if let serde_json::Value::Array(scheds) = &res["scx_schedulers"] { + for sched in scheds { + let sched = sched["name"].as_str().to_owned().unwrap().to_string(); + let sched_checkbutton = gtk::CheckButton::builder() + .valign(Align::Center) + .can_focus(false) + .build(); + let branch_row = adw::ActionRow::builder() + .activatable_widget(&sched_checkbutton) + .title(sched) + .build(); + branch_row.add_prefix(&sched_checkbutton); + sched_checkbutton.set_group(Some(&null_checkbutton)); + sched_container.append(&branch_row); + sched_checkbutton.connect_toggled( + clone!(@weak sched_checkbutton, @weak expander_row => move |_| { + if sched_checkbutton.is_active() == true { + expander_row.set_title(&branch_row.title()); + } + }), + ); + //if current_keyboard.contains(&(keyboard_layout_clone)) { + // keyboard_layout_checkbutton.set_active(true); + //} + } + }; + + let branch_container_viewport = gtk::ScrolledWindow::builder() + .child(&sched_container) + .hscrollbar_policy(PolicyType::Never) + .height_request(160) + .build(); + + sched_container.add_css_class("round-border-only-bottom"); + + boxedlist.append(&branch_container_viewport); + + searchbar.connect_search_changed(clone!(@weak searchbar, @weak sched_container => move |_| { + let mut counter = sched_container.first_child(); + while let Some(row) = counter { + if row.widget_name() == "AdwActionRow" { + if !searchbar.text().is_empty() { + if row.property::("subtitle").to_lowercase().contains(&searchbar.text().to_string().to_lowercase()) || row.property::("title").to_lowercase().contains(&searchbar.text().to_string().to_lowercase()) { + //row.grab_focus(); + //row.add_css_class("highlight-widget"); + row.set_property("visible", true); + searchbar.grab_focus(); + } else { + row.set_property("visible", false); + } + } else { + row.set_property("visible", true); + } + } + counter = row.next_sibling(); + } + })); + + boxedlist +} diff --git a/src/main.rs b/src/main.rs index 591bdaf..46ba27d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ mod build_ui; mod content; +mod kernel_pkg; mod sched_ext; use adw::prelude::*;