diff --git a/custom.css b/custom.css new file mode 100644 index 0000000..c9ce581 --- /dev/null +++ b/custom.css @@ -0,0 +1,10 @@ +/* +È possibile digitare qui qualsiasi regola CSS riconosciuta da GTK+. +È possibile disabilitare temporaneamente questo CSS personalizzato facendo clic sul pulsante «Pausa». + +Le modifiche sono applicate immediatamente e globalmente, per tutta l'applicazione. +*/ + +vte-terminal { + border: 3px solid red; +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 438e0f9..b403bfb 100644 --- a/src/main.rs +++ b/src/main.rs @@ -22,21 +22,46 @@ fn build_ui(application: >k::Application) { if let Some(settings) = window.get_settings() { settings.set_property_gtk_enable_animations(false); } + let w_state = WindowState::new_arc(WindowPos::Hidden, FullScreenState::NotFull); + let w_state0 = w_state.clone(); + let w_state1 = w_state.clone(); + let w_state2 = w_state.clone(); + let w_state3 = w_state.clone(); + let w_state4 = w_state.clone(); + let w_state5 = w_state.clone(); + let w_state6 = w_state.clone(); + let w_state7 = w_state.clone(); - window.set_title("First GTK+ Program"); + window.set_title("Waydrop"); window.set_border_width(0); window.move_(0, 0); //window.maximize(); window.set_position(gtk::WindowPosition::None); window.set_type_hint(gdk::WindowTypeHint::Dock); window.set_gravity(gdk::Gravity::NorthWest); - window.set_default_size(1920, 500); + window.set_default_size(1920, 700); window.set_decorated(false); window.set_can_focus(true); window.set_keep_above(true); let nb = gtk::Notebook::new(); - nb.set_show_tabs(false); + let css = gtk::CssProvider::new(); + css.load_from_data( + br#" + notebook { + border-bottom: 1px solid #657b83; + } + vte-terminal { + padding: 0; + margin: 0; + } + "#, + ) + .expect("Css errato"); + let sc = window.get_screen().unwrap(); + gtk::StyleContext::add_provider_for_screen(&sc, &css, 1000000); + nb.set_show_tabs(true); + nb.set_tab_pos(gtk::PositionType::Top); nb.set_scrollable(true); nb.set_show_border(false); let accel_group = gtk::AccelGroup::new(); @@ -46,7 +71,7 @@ fn build_ui(application: >k::Application) { modifier, gtk::AccelFlags::VISIBLE, clone!(@weak window, @weak nb => @default-return true, move |_accel_g, _window, _key, _modif| { - tabs::open_tab(&window, &nb, true, None, None, None); + tabs::open_tab(&window, &nb, true, None, None, None, &w_state6); true }), ); @@ -108,12 +133,6 @@ fn build_ui(application: >k::Application) { }), ); let (key, modifier) = gtk::accelerator_parse("F11"); - let w_state = WindowState::new_arc(WindowPos::Hidden, FullScreenState::NotFull); - let w_state0 = w_state.clone(); - let w_state1 = w_state.clone(); - let w_state2 = w_state.clone(); - let w_state3 = w_state.clone(); - let w_state4 = w_state.clone(); accel_group.connect_accel_group( key, modifier, @@ -149,7 +168,7 @@ fn build_ui(application: >k::Application) { window.add_accel_group(&accel_group); window.add(&nb); - if let Ok(first_tab) = tabs::build_tab(&nb, None, None) { + if let Ok(first_tab) = tabs::build_tab(&nb, None, None, &w_state5) { tabs::go_to_tab(&window, &nb, &first_tab); } window.set_skip_taskbar_hint(true); @@ -176,13 +195,13 @@ fn build_ui(application: >k::Application) { nb.connect_page_removed(clone!(@weak window => move |notebook, _vte, _index| { if notebook.get_n_pages() == 0 { if w_state0.get_pos() != WindowPos::Closing { - crate::tabs::open_tab(&window, ¬ebook, false,None, None, None); + crate::tabs::open_tab(&window, ¬ebook, false,None, None, None, &w_state5); window_state::hide(&window, &w_state0); } } else { tabs::set_titles(¬ebook); if notebook.get_n_pages() == 1 { - notebook.set_show_tabs(false); + notebook.set_show_tabs(true); } } })); @@ -209,11 +228,11 @@ fn build_ui(application: >k::Application) { } RunShell { cwd, shell } => { tira_su(); - tabs::open_tab(&window, &nb, true, cwd, Some(shell), None); + tabs::open_tab(&window, &nb, true, cwd, Some(shell), None, &w_state7); } RunInDefaultShell { cwd, command } => { tira_su(); - tabs::open_tab(&window, &nb, true, cwd, None, Some(command)); + tabs::open_tab(&window, &nb, true, cwd, None, Some(command), &w_state7); } RunInCustomShell { cwd, @@ -221,7 +240,7 @@ fn build_ui(application: >k::Application) { command, } => { tira_su(); - tabs::open_tab(&window, &nb, true, cwd, Some(shell), Some(command)); + tabs::open_tab(&window, &nb, true, cwd, Some(shell), Some(command), &w_state7); } } glib::Continue(true) diff --git a/src/tabs.rs b/src/tabs.rs index f3f3f59..c702b50 100644 --- a/src/tabs.rs +++ b/src/tabs.rs @@ -3,16 +3,30 @@ use gtk::prelude::*; use std::{env::var, path::Path}; use vte::TerminalExt; +use crate::window_state::{RcState, StateOperations}; + pub fn build_tab( nb: >k::Notebook, cwd: Option, shell: Option>, + w_state: &RcState, ) -> Result { let l = gtk::Label::new(Some("~")); l.set_ellipsize(pango::EllipsizeMode::Middle); //gtk::Window::set_interactive_debugging(true); let vte = vte::Terminal::new(); vte.set_scrollback_lines(-1); + // let sty = vte.get_style_context(); + // let css = gtk::CssProvider::new(); + // css.load_from_data( + // br#" + // * { + // padding: 10px; + // margin: 10px; + // }"#, + // ) + // .expect("errore css"); + // sty.add_provider(&css, 10000); let font = pango::FontDescription::from_string("Iosevka Regular 13"); vte.set_font(Some(&font)); @@ -51,6 +65,18 @@ pub fn build_tab( } gtk::Inhibit(false) }); + let wsc1 = w_state.clone(); + let wsc2 = w_state.clone(); + w_state.set_char_h(Some(vte.get_char_height() as u64)); + vte.connect_char_size_changed(move | _vte, _w, h| { + wsc1.set_char_h(Some(h as u64)); + }); + let nb2 = nb.clone(); + vte.connect_realize(move |vte|{ + let h = vte.get_allocated_size(); + let hn = nb2.get_allocated_size(); + wsc2.set_tab_h(Some((hn.0.height - h.0.height) as u64)); + }); vte.connect_window_title_changed(clone!(@weak nb => move |term| { set_title(term, &nb); @@ -58,25 +84,25 @@ pub fn build_tab( // Setto colori terminale use glib::translate::ToGlibPtr; use std::str::FromStr; - let fg = gdk::RGBA::from_str("#c5c5c8c8c6c6").unwrap_or(gdk::RGBA::white()); - let bg = gdk::RGBA::from_str("#1d1d1f1f2121").unwrap_or(gdk::RGBA::black()); + let fg = gdk::RGBA::from_str("#65657b7b8383").unwrap_or(gdk::RGBA::white()); + let bg = gdk::RGBA::from_str("#fdfdf6f6e3e3").unwrap_or(gdk::RGBA::black()); let palette = (&[ - "#1d1d1f1f2121", - "#cccc66666666", - "#b5b5bdbd6868", - "#f0f0c6c67474", - "#8181a2a2bebe", - "#b2b29494bbbb", - "#8a8abebeb7b7", - "#c5c5c8c8c6c6", - "#969698989696", - "#cccc66666666", - "#b5b5bdbd6868", - "#f0f0c6c67474", - "#8181a2a2bebe", - "#b2b29494bbbb", - "#8a8abebeb7b7", - "#ffffffffffff", + "#070736364242", + "#dcdc32322f2f", + "#858599990000", + "#b5b589890000", + "#26268b8bd2d2", + "#d3d336368282", + "#2a2aa1a19898", + "#eeeee8e8d5d5", + "#00002b2b3636", + "#cbcb4b4b1616", + "#58586e6e7575", + "#65657b7b8383", + "#838394949696", + "#6c6c7171c4c4", + "#9393a1a1a1a1", + "#fdfdf6f6e3e3", ]) .iter() .map(|&s| gdk::RGBA::from_str(s).unwrap_or(gdk::RGBA::from_str("#ffffff").unwrap())); @@ -93,10 +119,9 @@ pub fn build_tab( Ok(vte) } fn set_title(term: &vte::Terminal, nb: >k::Notebook) { - let tab_n = if let Some(num) = nb.page_num(term) { - format!("{}. ", num + 1) - } else { - "".to_string() + let tab_n = match nb.page_num(term) { + Some(num) => format!("{}. ", num + 1), + None => "".to_string(), }; if let Some(l) = nb.get_tab_label(term) { if let Ok(l) = l.downcast::() { @@ -146,8 +171,9 @@ pub fn open_tab( cwd: Option, shell: Option>, inject_command: Option, + w_state: &RcState, ) { - let new_tab = build_tab(nb, cwd, shell); + let new_tab = build_tab(nb, cwd, shell, w_state); if let Ok(new_tab) = new_tab { window.show_all(); if focus { diff --git a/src/window_state.rs b/src/window_state.rs index 03e599b..a08cbf2 100644 --- a/src/window_state.rs +++ b/src/window_state.rs @@ -1,7 +1,6 @@ use gdk::WindowExt; use gtk::prelude::*; -use std::rc::Rc; -use std::sync::RwLock; +use std::sync::{Arc, RwLock}; use std::time::{Duration, Instant}; #[derive(Eq, PartialEq, Debug, Copy, Clone)] @@ -24,14 +23,19 @@ pub use FullScreenState::*; pub use WindowPos::*; pub struct WindowState { position: WindowPos, + char_h: Option, + tab_h: Option, full: FullScreenState, last_toggle: Option, focus_lost: Option, } +pub type RcState = Arc>; impl WindowState { - pub fn new_arc(p: WindowPos, f: FullScreenState) -> Rc> { - Rc::new(RwLock::new(WindowState { + pub fn new_arc(p: WindowPos, f: FullScreenState) -> RcState { + Arc::new(RwLock::new(WindowState { full: f, + char_h: None, + tab_h: None, position: p, last_toggle: None, focus_lost: None, @@ -43,12 +47,16 @@ pub trait StateOperations { fn get_pos(&self) -> WindowPos; fn set_full(&self, f: FullScreenState); fn get_full(&self) -> FullScreenState; + fn get_char_h(&self) -> Option; + fn set_char_h(&self, char_h: Option); + fn get_tab_h(&self) -> Option; + fn set_tab_h(&self, tab_h: Option); fn set_last_toggle(&self, instant: Option); fn get_last_toggle(&self) -> Option; fn set_focus_lost(&self, instant: Option); fn get_focus_lost(&self) -> Option; } -impl StateOperations for Rc> { +impl StateOperations for RcState { fn set_pos(&self, p: WindowPos) { if let Ok(mut w_lock) = self.write() { w_lock.position = p; @@ -77,6 +85,20 @@ impl StateOperations for Rc> { FullScreenState::Unknown } } + fn get_char_h(&self) -> Option { + if let Ok(r_lock) = self.read() { + r_lock.char_h + } else { + None + } + } + fn get_tab_h(&self) -> Option { + if let Ok(r_lock) = self.read() { + r_lock.tab_h + } else { + None + } + } fn get_last_toggle(&self) -> Option { if let Ok(r_lock) = self.read() { r_lock.last_toggle @@ -105,9 +127,23 @@ impl StateOperations for Rc> { eprintln!("Can't acquire lock"); } } + fn set_char_h(&self, char_h: Option) { + if let Ok(mut w_lock) = self.write() { + w_lock.char_h = char_h; + } else { + eprintln!("Can't acquire lock"); + } + } + fn set_tab_h(&self, tab_h: Option) { + if let Ok(mut w_lock) = self.write() { + w_lock.tab_h = tab_h; + } else { + eprintln!("Can't acquire lock"); + } + } } -pub fn bring_up(window: >k::ApplicationWindow, w_state: &Rc>, ts: u32) { +pub fn bring_up(window: >k::ApplicationWindow, w_state: &RcState, ts: u32) { if let Some(instant) = w_state.get_last_toggle() { if instant.elapsed() < Duration::from_millis(300) { return; @@ -141,7 +177,7 @@ pub fn bring_up(window: >k::ApplicationWindow, w_state: &Rc>) { +pub fn hide(window: >k::ApplicationWindow, stato: &RcState) { stato.set_pos(Hiding); window.hide(); } -pub fn esegui_toggle( - window: >k::ApplicationWindow, - nb: >k::Notebook, - w_state: &Rc>, -) { +pub fn esegui_toggle(window: >k::ApplicationWindow, nb: >k::Notebook, w_state: &RcState) { let ts = gtk::get_current_event_time(); let pos = w_state.get_pos(); match pos { @@ -183,7 +215,7 @@ pub fn esegui_toggle( } } -pub fn focus_out(w_state: &Rc>) -> gtk::Inhibit { +pub fn focus_out(w_state: &RcState) -> gtk::Inhibit { // eprintln!("<<<<<<<<<<<< Focus out!"); w_state.set_focus_lost(Some(Instant::now())); let pos = w_state.get_pos(); @@ -198,13 +230,10 @@ pub fn focus_out(w_state: &Rc>) -> gtk::Inhibit { gtk::Inhibit(false) } -pub fn focus_in( - window: >k::ApplicationWindow, - w_state: &Rc>, -) -> gtk::Inhibit { +pub fn focus_in(window: >k::ApplicationWindow, w_state: &RcState) -> gtk::Inhibit { //eprintln!(">>>>>>>>>>> Focus in!"); w_state.set_pos(Up); - let s = calc_w_h(window); + let s = calc_w_h(window, w_state); window.set_type_hint(gdk::WindowTypeHint::Dock); if let Some((_x, _y, width, height)) = window.get_window().and_then(|x| Some(x.get_geometry())) { @@ -218,11 +247,15 @@ pub fn focus_in( gtk::Inhibit(false) } -pub fn calc_w_h(window: >k::ApplicationWindow) -> (i32, i32) { - window +pub fn calc_w_h(window: >k::ApplicationWindow, w_state: &RcState) -> (i32, i32) { + //let (rounding, tab_h) = w_state.get_char_tab_h(); + let rounding = w_state.get_char_h().unwrap() as i32; + let tab_h = w_state.get_tab_h().unwrap() as i32; + let wh = window .get_window() .and_then(|gdk_win| gdk_win.get_display().get_monitor_at_window(&gdk_win)) .map(|mon| mon.get_geometry()) .and_then(|gdk::Rectangle { width, height, .. }| Some((width, height / 2))) - .unwrap_or((1920, 540)) + .unwrap_or((1920, 540)); + (wh.0, wh.1 - wh.1 % rounding + tab_h) }