From 296985d382aba56f4bc6b4dee06b7721deaaa1a9 Mon Sep 17 00:00:00 2001 From: Pietro Brenna Date: Fri, 13 Mar 2020 23:54:37 +0100 Subject: [PATCH] =?UTF-8?q?=C3=88=20cos=C3=AC=20perfetto=20che=20non=20si?= =?UTF-8?q?=20chiama=20pi=C3=B9=20cacca?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 29 +++++----- Cargo.toml | 5 +- src/main.rs | 90 ++++++++++++++++-------------- src/menu.rs | 24 ++++---- src/stato_finestra.rs | 20 ++++--- src/tabs.rs | 124 ++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 213 insertions(+), 79 deletions(-) create mode 100644 src/tabs.rs diff --git a/Cargo.lock b/Cargo.lock index 309e0e2..031c5d0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -38,20 +38,6 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -[[package]] -name = "cacca" -version = "0.1.0" -dependencies = [ - "crossbeam-channel", - "gdk", - "gdk-sys", - "gio", - "glib", - "gtk", - "pango", - "vte-rs", -] - [[package]] name = "cairo-rs" version = "0.8.1" @@ -507,3 +493,18 @@ dependencies = [ "pango-sys", "pkg-config", ] + +[[package]] +name = "waydrop" +version = "0.1.0" +dependencies = [ + "crossbeam-channel", + "gdk", + "gdk-sys", + "gio", + "glib", + "gtk", + "pango", + "vte-rs", + "vte-sys", +] diff --git a/Cargo.toml b/Cargo.toml index f234fc8..85f4dff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "cacca" +name = "waydrop" version = "0.1.0" authors = ["Pietro Brenna "] edition = "2018" @@ -8,6 +8,7 @@ edition = "2018" [dependencies] vte-rs = "*" +vte-sys = "*" gio = "*" gtk = "*" gdk-sys="*" @@ -17,7 +18,7 @@ crossbeam-channel="*" glib = "*" [[bin]] -name = "cacca" +name = "waydrop" path = "src/main.rs" [[bin]] diff --git a/src/main.rs b/src/main.rs index 5555f84..9bb4fd8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,16 +4,17 @@ extern crate vte; use gio::prelude::*; use gtk::prelude::*; -use vte::TerminalExt; +use glib::clone; +use glib::translate::{ToGlib, ToGlibPtr}; use gtk::SettingsExt; use std::env::args; use std::sync::{Arc, RwLock}; use std::thread; -use glib::translate::{ToGlibPtr, ToGlib}; mod menu; mod stato_finestra; +mod tabs; mod wake_listener; fn build_ui(application: >k::Application) { @@ -31,65 +32,70 @@ fn build_ui(application: >k::Application) { window.set_can_focus(true); window.set_keep_above(true); let nb = gtk::Notebook::new(); - let l = gtk::Label::new(Some("Prova1")); - //gtk::Window::set_interactive_debugging(true); - let vte = vte::Terminal::new(); + nb.set_show_tabs(false); + nb.set_show_border(false); let accel_group = gtk::AccelGroup::new(); - let (key,modifier) = gtk::accelerator_parse("c"); - vte.add_accelerator("copy-clipboard", &accel_group, key, modifier, gtk::AccelFlags::VISIBLE); + let (key, modifier) = gtk::accelerator_parse("t"); + accel_group.connect_accel_group( + key, + modifier, + gtk::AccelFlags::VISIBLE, + clone!(@weak window, @weak nb => @default-return true, move |accel_g, _window, _key, _modif| { + tabs::apri_tab(&window, &nb, &accel_g, true); + true + }), + ); window.add_accel_group(&accel_group); - let font = pango::FontDescription::from_string("Iosevka Regular 13"); - vte.set_font(Some(&font)); - let c = gio::Cancellable::get_current(); - let pid = vte - .spawn_sync( - vte::PtyFlags::DEFAULT, - None, - &[&std::path::PathBuf::from("/usr/bin/fish")], - &[], - glib::SpawnFlags::DEFAULT, - Some(&mut || {}), - c.as_ref(), - ) - .unwrap(); - vte.watch_child(pid); - nb.set_show_border(false); - nb.append_page(&vte, Some(&l)); - window.add(&nb); - + let first_tab = tabs::build_tab(&nb, &accel_group); window.set_skip_taskbar_hint(true); window.set_skip_pager_hint(true); - window.set_focus(Some(&vte)); window.show_all(); + tabs::passa_a_tab(&window, &nb, &first_tab); unsafe { - gdk_sys::gdk_window_set_skip_pager_hint(window.get_window().unwrap().to_glib_none().0, true.to_glib()); - gdk_sys::gdk_window_set_skip_taskbar_hint(window.get_window().unwrap().to_glib_none().0, true.to_glib()); + gdk_sys::gdk_window_set_skip_pager_hint( + window.get_window().unwrap().to_glib_none().0, + true.to_glib(), + ); + gdk_sys::gdk_window_set_skip_taskbar_hint( + window.get_window().unwrap().to_glib_none().0, + true.to_glib(), + ); } let stato = Arc::new(RwLock::new(stato_finestra::StatoFinestra::Su)); let stato1 = stato.clone(); let stato2 = stato.clone(); + let stato3 = stato.clone(); + let stato4 = stato.clone(); + + //let cloned_app = application.clone(); - let cloned_app = application.clone(); - vte.connect_child_exited(move |_a, status| { - println!("Child exited with status {}", status); - cloned_app.quit(); - }); window.connect_focus_out_event(move |_widget, _b| stato_finestra::focus_out(&stato1)); window.connect_focus_in_event(move |_widget, _b| stato_finestra::focus_in(&stato2)); - vte.connect_popup_menu(move |ref vte| menu::menu(vte, None)); - vte.connect_button_press_event(move |ref vte, ev| { - if ev.get_event_type() == gdk::EventType::ButtonPress && - ev.get_button() == gdk_sys::GDK_BUTTON_SECONDARY as u32 { - menu::menu(vte, Some(ev.get_button())); + nb.connect_page_removed(clone!(@weak window, @weak accel_group => move |notebook, _vte, _index| { + if notebook.get_n_pages() == 0 { + if let Ok(ref mut lock_stato) = stato.write() { + tabs::apri_tab(&window, ¬ebook, &accel_group, false); + stato_finestra::butta_giu(&window, lock_stato); + } + } else if notebook.get_n_pages() == 1 { + notebook.set_show_tabs(false); + } + })); + nb.connect_page_added(move |notebook, _vte, _index|{ + if notebook.get_n_pages() > 1 { + notebook.set_show_tabs(true); } - gtk::Inhibit(false) }); + let (tx, rx) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); - stato_finestra::focussa(&window, &vte, gtk::get_current_event_time()); + if let Ok(ref mut lock_stato) = stato4.write() { + stato_finestra::tira_su(&window, lock_stato, gtk::get_current_event_time()); + } + //tabs::focus_tab_corrente(&nb); rx.attach(None, move |_cmd| { - stato_finestra::esegui_toggle(&window, &vte, &stato) + stato_finestra::esegui_toggle(&window, &nb, &stato3) }); thread::spawn(move || { wake_listener::listener(&tx); diff --git a/src/menu.rs b/src/menu.rs index 1f40283..a1e5f44 100644 --- a/src/menu.rs +++ b/src/menu.rs @@ -1,17 +1,15 @@ use gdk::Atom; +use glib::clone; use gtk::prelude::*; use gtk::{Menu, MenuItemBuilder}; use vte::TerminalExt; pub fn menu(widget: &vte::Terminal, btn: Option) -> bool { let clipboard = widget.get_clipboard(&Atom::intern("CLIPBOARD")); - let w1 = widget.clone(); - let w2 = widget.clone(); - let w3 = widget.clone(); - clipboard.request_text(move |_clipboard, maybe_str| { + clipboard.request_text(clone!(@weak widget => move |_clipboard, maybe_str| { let ctx_menu = Menu::new(); let cpy = MenuItemBuilder::new() .label("Copy") - .sensitive(w3.get_has_selection()) + .sensitive(widget.get_has_selection()) .parent(&ctx_menu) .build(); let paste = MenuItemBuilder::new() @@ -19,15 +17,15 @@ pub fn menu(widget: &vte::Terminal, btn: Option) -> bool { .sensitive(maybe_str.is_some() && maybe_str != Some("")) .parent(&ctx_menu) .build(); - cpy.connect_activate(move |_m| { - w1.copy_clipboard(); - }); - paste.connect_activate(move |_m| { - w2.paste_clipboard(); - }); + cpy.connect_activate(clone!(@weak widget => move |_m| { + widget.copy_clipboard(); + })); + paste.connect_activate(clone!(@weak widget => move |_m| { + widget.paste_clipboard(); + })); ctx_menu.show_all(); - ctx_menu.set_property_attach_widget(Some(&w3)); + ctx_menu.set_property_attach_widget(Some(&widget)); ctx_menu.popup_easy(btn.unwrap_or(1), gtk::get_current_event_time()); - }); + })); true } diff --git a/src/stato_finestra.rs b/src/stato_finestra.rs index ca0d8aa..d9c1dde 100644 --- a/src/stato_finestra.rs +++ b/src/stato_finestra.rs @@ -10,7 +10,7 @@ use gdk::WindowExt; use gtk::prelude::*; use std::sync::{Arc, RwLock}; -pub fn focussa(window: >k::ApplicationWindow, vte: &impl glib::IsA, ts: u32) { +pub fn tira_su(window: >k::ApplicationWindow, stato: &mut StatoFinestra, ts: u32) { // Shameless copy from guake window.present(); window.deiconify(); @@ -19,32 +19,36 @@ pub fn focussa(window: >k::ApplicationWindow, vte: &impl glib::IsA, + nb: >k::Notebook, stato: &Arc>, ) -> glib::source::Continue { let ts = gtk::get_current_event_time(); if let Ok(mut inner) = stato.write() { match *inner { StatoFinestra::Nascosta | StatoFinestra::Nascondendo => { - *inner = StatoFinestra::TirandoSu; - focussa(window, vte, ts); + tira_su(window, &mut inner, ts); + crate::tabs::focus_tab_corrente(&nb); } StatoFinestra::SuNonFocusata => { window.hide(); window.show(); window.get_window().unwrap().focus(ts); window.get_window().unwrap().focus(0); - window.set_focus(Some(vte)); + crate::tabs::focus_tab_corrente(&nb); *inner = StatoFinestra::Su; } StatoFinestra::Su => { - *inner = StatoFinestra::Nascondendo; - window.hide(); + butta_giu(window, &mut inner) } _ => {} } diff --git a/src/tabs.rs b/src/tabs.rs new file mode 100644 index 0000000..1a0677b --- /dev/null +++ b/src/tabs.rs @@ -0,0 +1,124 @@ +use glib::clone; +use gtk::prelude::*; +use vte::TerminalExt; + +pub fn build_tab(nb: >k::Notebook, w_accel_group: >k::AccelGroup) -> vte::Terminal { + let l = gtk::Label::new(Some("~")); + l.set_width_chars(10); + l.set_ellipsize(pango::EllipsizeMode::Start); + //gtk::Window::set_interactive_debugging(true); + let vte = vte::Terminal::new(); + let (key, modifier) = gtk::accelerator_parse("c"); + vte.add_accelerator( + "copy-clipboard", + w_accel_group, + key, + modifier, + gtk::AccelFlags::VISIBLE, + ); + + let font = pango::FontDescription::from_string("Iosevka Regular 13"); + vte.set_font(Some(&font)); + let c = gio::Cancellable::get_current(); + let pid = vte + .spawn_sync( + vte::PtyFlags::DEFAULT, + None, + &[&std::path::PathBuf::from("/usr/bin/fish")], + &[], + glib::SpawnFlags::DEFAULT, + Some(&mut || {}), + c.as_ref(), + ) + .unwrap(); + vte.watch_child(pid); + nb.append_page(&vte, Some(&l)); + nb.set_tab_reorderable(&vte, true); + vte.connect_child_exited(clone!(@weak nb, @weak vte => move |_a, status| { + println!("Child exited with status {}", status); + let p_num = nb.page_num(&vte); + nb.remove_page(p_num); + })); + vte.connect_popup_menu(move |ref vte| crate::menu::menu(vte, None)); + vte.connect_button_press_event(move |ref vte, ev| { + if ev.get_event_type() == gdk::EventType::ButtonPress + && ev.get_button() == gdk_sys::GDK_BUTTON_SECONDARY as u32 + { + crate::menu::menu(vte, Some(ev.get_button())); + } + gtk::Inhibit(false) + }); + + vte.connect_window_title_changed(move |term| { + if let Some(title) = term.get_window_title() { + l.set_label(&title); + } else { + l.set_label(""); + } + }); + // 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 palette = (&[ + "#1d1d1f1f2121", + "#cccc66666666", + "#b5b5bdbd6868", + "#f0f0c6c67474", + "#8181a2a2bebe", + "#b2b29494bbbb", + "#8a8abebeb7b7", + "#c5c5c8c8c6c6", + "#969698989696", + "#cccc66666666", + "#b5b5bdbd6868", + "#f0f0c6c67474", + "#8181a2a2bebe", + "#b2b29494bbbb", + "#8a8abebeb7b7", + "#ffffffffffff", + ]) + .iter() + .map(|&s| gdk::RGBA::from_str(s).unwrap_or(gdk::RGBA::from_str("#ffffff").unwrap())); + unsafe { + let unsafe_palette: Vec<_> = palette.map(|x| *x.to_glib_none().0).collect(); + vte_sys::vte_terminal_set_colors( + vte.to_glib_none().0, + fg.to_glib_none().0, + bg.to_glib_none().0, + unsafe_palette.as_ptr(), + unsafe_palette.len(), + ); + } + vte +} + +pub fn passa_a_tab(win: >k::ApplicationWindow, nb: >k::Notebook, vte: &vte::Terminal) { + let p_num = nb.page_num(vte); + nb.set_current_page(p_num); + win.set_focus(Some(vte)); +} +pub fn focus_tab_corrente(nb: >k::Notebook) { + let n_p = nb.get_current_page(); + let vte = nb.get_nth_page(n_p); + if let Some(vte) = vte { + if let Some(win) = nb.get_toplevel() { + if let Ok(win) = win.downcast::() { + win.set_focus(Some(&vte)); + } + } + } +} +pub fn apri_tab( + window: >k::ApplicationWindow, + nb: >k::Notebook, + accel_g: >k::AccelGroup, + focus: bool, +) { + let new_tab = build_tab(&nb, accel_g); + window.show_all(); + if focus { + crate::tabs::passa_a_tab(&window, &nb, &new_tab); + } +}