From 454f84c5aebdc3e49ebf042d7734de8323b2f7f2 Mon Sep 17 00:00:00 2001 From: Pietro Brenna Date: Sun, 15 Mar 2020 15:46:19 +0100 Subject: [PATCH] Tante cose --- Cargo.lock | 32 +++++++++ Cargo.toml | 16 +++-- src/main.rs | 149 +++++++++++++++++++++++++++++++++++------- src/stato_finestra.rs | 86 ++++++++++++++++-------- src/tabs.rs | 107 +++++++++++++++++++++--------- src/toggle.rs | 30 +++++++++ src/wake.rs | 7 -- src/wake_listener.rs | 64 ++++++++++++------ waydrop.desktop | 8 +++ 9 files changed, 389 insertions(+), 110 deletions(-) create mode 100644 src/toggle.rs delete mode 100644 src/wake.rs create mode 100644 waydrop.desktop diff --git a/Cargo.lock b/Cargo.lock index 031c5d0..49d01e8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -96,6 +96,25 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "dbus" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "acd824d45fad5ff0e178fcb3c040f13780e73f63a0a6d5cde59e7894f251ab0e" +dependencies = [ + "libc", + "libdbus-sys", +] + +[[package]] +name = "dbus-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efc7077f517382c729c845ea59d2e36a9946f5e0dd837e589a287d87535a4730" +dependencies = [ + "dbus", +] + [[package]] name = "futures-channel" version = "0.3.4" @@ -352,6 +371,15 @@ version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" +[[package]] +name = "libdbus-sys" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8720f9274907052cb50313f91201597868da9d625f8dd125f2aca5bddb7e83a1" +dependencies = [ + "pkg-config", +] + [[package]] name = "maybe-uninit" version = "2.0.0" @@ -499,10 +527,14 @@ name = "waydrop" version = "0.1.0" dependencies = [ "crossbeam-channel", + "dbus", + "dbus-macros", "gdk", "gdk-sys", "gio", + "gio-sys", "glib", + "glib-sys", "gtk", "pango", "vte-rs", diff --git a/Cargo.toml b/Cargo.toml index 85f4dff..336a554 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,20 +7,28 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -vte-rs = "*" +vte-rs = "^0.3" vte-sys = "*" gio = "*" -gtk = "*" +gio-sys = "*" +gtk = {version = "*", features = ["v3_22"]} gdk-sys="*" gdk = "*" pango = "*" crossbeam-channel="*" glib = "*" +glib-sys = "*" +# jsonrpc-ipc-server = "^14.0" +# jsonrpc-derive = "*" +# jsonrpc-core = "*" +# jsonrpc-core-client = "*" +dbus = "*" +dbus-macros = "*" [[bin]] name = "waydrop" path = "src/main.rs" [[bin]] -name = "wake" -path = "src/wake.rs" \ No newline at end of file +name = "waydrop-toggle" +path = "src/toggle.rs" \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 9bb4fd8..235c092 100644 --- a/src/main.rs +++ b/src/main.rs @@ -6,7 +6,6 @@ use gio::prelude::*; use gtk::prelude::*; use glib::clone; -use glib::translate::{ToGlib, ToGlibPtr}; use gtk::SettingsExt; use std::env::args; use std::sync::{Arc, RwLock}; @@ -26,6 +25,10 @@ fn build_ui(application: >k::Application) { window.set_title("First GTK+ Program"); 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_decorated(false); @@ -41,19 +44,71 @@ 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::apri_tab(&window, &nb, &accel_g, true); + tabs::apri_tab(&window, &nb, true, None, None, None); true }), ); + let (key, modifier) = gtk::accelerator_parse("Page_Down"); + accel_group.connect_accel_group( + key, + modifier, + gtk::AccelFlags::VISIBLE, + clone!(@weak nb => @default-return true, move |_accel_g, _window, _key, _modif| { + nb.next_page(); + true + }), + ); + let (key, modifier) = gtk::accelerator_parse("Page_Up"); + accel_group.connect_accel_group( + key, + modifier, + gtk::AccelFlags::VISIBLE, + clone!(@weak nb => @default-return true, move |_accel_g, _window, _key, _modif| { + nb.prev_page(); + true + }), + ); + let (key, modifier) = gtk::accelerator_parse("F11"); + let full_screen = Arc::new(RwLock::new(false)); + accel_group.connect_accel_group( + key, + modifier, + gtk::AccelFlags::VISIBLE, + clone!(@weak window => @default-return true, move |_accel_g, _win, _key, _modif| { + if let Ok(mut lock) = full_screen.write(){ + if *lock { + window.unfullscreen(); + } else { + window.fullscreen(); + } + *lock = !*lock; + } + true + }), + ); + for i in 1..9 { + let (key, modifier) = gtk::accelerator_parse(&format!("{}", i)); + accel_group.connect_accel_group( + key, + modifier, + gtk::AccelFlags::VISIBLE, + clone!(@weak nb => @default-return true, move |_accel_g, _win, _key, _modif| { + nb.set_current_page(Some(i-1)); + true + }), + ); + } + window.add_accel_group(&accel_group); window.add(&nb); - let first_tab = tabs::build_tab(&nb, &accel_group); + if let Ok(first_tab) = tabs::build_tab(&window, &nb, None, None) { + tabs::passa_a_tab(&window, &nb, &first_tab); + } window.set_skip_taskbar_hint(true); window.set_skip_pager_hint(true); window.show_all(); - tabs::passa_a_tab(&window, &nb, &first_tab); - unsafe { + /*unsafe { gdk_sys::gdk_window_set_skip_pager_hint( window.get_window().unwrap().to_glib_none().0, true.to_glib(), @@ -62,43 +117,93 @@ fn build_ui(application: >k::Application) { window.get_window().unwrap().to_glib_none().0, true.to_glib(), ); - } + }*/ let stato = Arc::new(RwLock::new(stato_finestra::StatoFinestra::Su)); + let stato0 = stato.clone(); let stato1 = stato.clone(); let stato2 = stato.clone(); let stato3 = stato.clone(); let stato4 = stato.clone(); - //let cloned_app = application.clone(); - 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)); - 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); + window.connect_focus_in_event(clone!(@weak window => @default-return gtk::Inhibit(false), + move |_widget, _b| stato_finestra::focus_in(&window, &stato2))); + nb.connect_destroy(move |_nb| { + if let Ok(mut lock_stato) = stato.write() { + *lock_stato = stato_finestra::StatoFinestra::Chiudendo; } - })); - nb.connect_page_added(move |notebook, _vte, _index|{ + }); + nb.connect_page_removed( + clone!(@weak window => move |notebook, _vte, _index| { + if notebook.get_n_pages() == 0 { + if let Ok(mut lock_stato) = stato0.write() { + if *lock_stato != stato_finestra::StatoFinestra::Chiudendo { + crate::tabs::apri_tab(&window, ¬ebook, false,None, None, None); + stato_finestra::butta_giu(&window, &mut lock_stato); + } + } + } else { + tabs::set_titles(¬ebook); + if notebook.get_n_pages() == 1 { + notebook.set_show_tabs(false); + } + } + dbg!(); + }), + ); + nb.connect_page_added(move |notebook, _vte, _index| { if notebook.get_n_pages() > 1 { notebook.set_show_tabs(true); } }); + nb.connect_page_reordered(move |notebook, _vte, _index| { + tabs::set_titles(¬ebook); + }); let (tx, rx) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); 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, &nb, &stato3) + rx.attach(None, move |cmd| { + let tira_su = || { + if let Ok(ref mut lock_stato) = stato3.write() { + stato_finestra::tira_su(&window, lock_stato, gtk::get_current_event_time()); + } + }; + use wake_listener::RpcCommand::*; + match cmd { + Toggle => { + stato_finestra::esegui_toggle(&window, &nb, &stato3); + } + RunShell { cwd, shell } => { + tira_su(); + tabs::apri_tab(&window, &nb, true, cwd, Some(shell), None); + } + RunInDefaultShell { cwd, command } => { + tira_su(); + tabs::apri_tab(&window, &nb, true, cwd, None, Some(command)); + } + RunInCustomShell { + cwd, + shell, + command, + } => { + tira_su(); + tabs::apri_tab( + &window, + &nb, + true, + cwd, + Some(shell), + Some(command), + ); + } + } + glib::Continue(true) }); thread::spawn(move || { - wake_listener::listener(&tx); + wake_listener::listener(tx); }); } diff --git a/src/stato_finestra.rs b/src/stato_finestra.rs index d9c1dde..47036d4 100644 --- a/src/stato_finestra.rs +++ b/src/stato_finestra.rs @@ -5,21 +5,44 @@ pub enum StatoFinestra { Nascondendo, Nascosta, SuNonFocusata, + Chiudendo, } use gdk::WindowExt; use gtk::prelude::*; use std::sync::{Arc, RwLock}; pub fn tira_su(window: >k::ApplicationWindow, stato: &mut StatoFinestra, ts: u32) { - // Shameless copy from guake - window.present(); - window.deiconify(); - window.show(); - window.get_window().unwrap().focus(ts); - window.set_type_hint(gdk::WindowTypeHint::Dock); - window.set_type_hint(gdk::WindowTypeHint::Normal); - window.get_window().unwrap().focus(0); - *stato = StatoFinestra::TirandoSu; + match *stato { + StatoFinestra::Nascosta | StatoFinestra::Nascondendo => { + // Shameless copy from guake + /*window.hide(); + window.present(); + window.deiconify();*/ + window.show(); + let gdk_window = window.get_window(); + if let Some(ref gdk_window) = gdk_window { + gdk_window.focus(ts); + } + window.set_type_hint(gdk::WindowTypeHint::Dock); + /*if let Some(ref gdk_window) = gdk_window { + gdk_window.focus(0); + }*/ + *stato = StatoFinestra::TirandoSu; + } + StatoFinestra::SuNonFocusata => { + window.hide(); + window.show(); + let gdk_window = window.get_window(); + if let Some(ref gdk_window) = gdk_window { + gdk_window.focus(ts); + gdk_window.focus(0); + } + let s = calc_w_h(window); + window.get_window().map(|w| w.resize(s.0, s.1)); + *stato = StatoFinestra::Su; + } + _ => {} + } } pub fn butta_giu(window: >k::ApplicationWindow, stato: &mut StatoFinestra) { @@ -31,32 +54,20 @@ pub fn esegui_toggle( window: >k::ApplicationWindow, 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 => { + StatoFinestra::Nascosta | StatoFinestra::Nascondendo | StatoFinestra::SuNonFocusata => { 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); crate::tabs::focus_tab_corrente(&nb); - *inner = StatoFinestra::Su; - } - StatoFinestra::Su => { - butta_giu(window, &mut inner) } + StatoFinestra::Su => butta_giu(window, &mut inner), _ => {} } } else { eprintln!("Can't acquire lock!"); } - println!("Stato: {:?}", stato); - glib::Continue(true) } pub fn focus_out(stato: &Arc>) -> gtk::Inhibit { @@ -68,14 +79,35 @@ pub fn focus_out(stato: &Arc>) -> gtk::Inhibit { //widget.unstick(); } } - println!("Stato: {:?}", stato); gtk::Inhibit(false) } -pub fn focus_in(stato: &Arc>) -> gtk::Inhibit { +pub fn focus_in( + window: >k::ApplicationWindow, + stato: &Arc>, +) -> gtk::Inhibit { if let Ok(mut inner) = stato.write() { *inner = StatoFinestra::Su; } - println!("Stato: {:?}", stato); + let s = calc_w_h(window); + window.set_type_hint(gdk::WindowTypeHint::Dock); + if let Some((_x, _y, width, height)) = window.get_window().and_then(|x| Some(x.get_geometry())) + { + if height != s.1 || width != s.0 { + window.hide(); + window.resize( s.0, s.1); + window.show(); + window.move_(0,0); + } + } gtk::Inhibit(false) } + +pub fn calc_w_h(window: >k::ApplicationWindow) -> (i32, i32) { + 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)) +} diff --git a/src/tabs.rs b/src/tabs.rs index 1a0677b..4f488af 100644 --- a/src/tabs.rs +++ b/src/tabs.rs @@ -1,17 +1,24 @@ use glib::clone; use gtk::prelude::*; +use std::{env::var, path::Path}; use vte::TerminalExt; -pub fn build_tab(nb: >k::Notebook, w_accel_group: >k::AccelGroup) -> vte::Terminal { +pub fn build_tab( + window: >k::ApplicationWindow, + nb: >k::Notebook, + cwd: Option, + shell: Option>, +) -> Result { + let new_accel_g = gtk::AccelGroup::new(); let l = gtk::Label::new(Some("~")); - l.set_width_chars(10); - l.set_ellipsize(pango::EllipsizeMode::Start); + l.set_width_chars(14); + l.set_ellipsize(pango::EllipsizeMode::Middle); //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, + &new_accel_g, key, modifier, gtk::AccelFlags::VISIBLE, @@ -20,22 +27,28 @@ pub fn build_tab(nb: >k::Notebook, w_accel_group: >k::AccelGroup) -> vte::Te 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); + let shell = shell.unwrap_or(vec![var("SHELL").unwrap_or("/bin/sh".to_string())]); + let shell: Vec<_> = shell.iter().map(Path::new).collect(); + let stringa: String; + let cwd = if cwd.is_some() { + stringa = cwd.unwrap(); + Some(stringa.as_str()) + } else { + None + }; + let _pid = vte.spawn_sync( + vte::PtyFlags::DEFAULT, + cwd, + &shell, + &[], + glib::SpawnFlags::DEFAULT, + Some(&mut || {}), + c.as_ref(), + )?; 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); + vte.connect_child_exited(clone!(@weak nb, @weak vte => move |a, status| { + println!("Child exited with status {:?} {}", a, status); let p_num = nb.page_num(&vte); nb.remove_page(p_num); })); @@ -49,13 +62,10 @@ pub fn build_tab(nb: >k::Notebook, w_accel_group: >k::AccelGroup) -> vte::Te 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(""); - } - }); + vte.connect_window_title_changed(clone!(@weak nb => move |term| { + set_title(term, &nb); + })); + window.add_accel_group(&new_accel_g); // Setto colori terminale use glib::translate::ToGlibPtr; use std::str::FromStr; @@ -91,7 +101,32 @@ pub fn build_tab(nb: >k::Notebook, w_accel_group: >k::AccelGroup) -> vte::Te unsafe_palette.len(), ); } - vte + 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() + }; + if let Some(l) = nb.get_tab_label(term) { + if let Ok(l) = l.downcast::() { + if let Some(title) = term.get_window_title() { + l.set_label(&format!("{}{}", tab_n, title)); + } else { + l.set_label(&tab_n); + } + } + } +} +pub fn set_titles(nb: >k::Notebook) { + for page_n in 0..nb.get_n_pages() { + if let Some(widget) = nb.get_nth_page(Some(page_n)) { + if let Ok(vte) = widget.downcast::() { + set_title(&vte, nb); + } + } + } } pub fn passa_a_tab(win: >k::ApplicationWindow, nb: >k::Notebook, vte: &vte::Terminal) { @@ -110,15 +145,25 @@ pub fn focus_tab_corrente(nb: >k::Notebook) { } } } +fn inject(term: &vte::Terminal, command: String) { + term.feed_child_binary(format!("{}\n", command.trim()).as_bytes()); +} pub fn apri_tab( window: >k::ApplicationWindow, nb: >k::Notebook, - accel_g: >k::AccelGroup, focus: bool, + cwd: Option, + shell: Option>, + inject_command: Option, ) { - let new_tab = build_tab(&nb, accel_g); - window.show_all(); - if focus { - crate::tabs::passa_a_tab(&window, &nb, &new_tab); + let new_tab = build_tab(window, nb, cwd, shell); + if let Ok(new_tab) = new_tab { + window.show_all(); + if focus { + crate::tabs::passa_a_tab(&window, &nb, &new_tab); + } + if let Some(command) = inject_command { + inject(&new_tab, command); + } } } diff --git a/src/toggle.rs b/src/toggle.rs new file mode 100644 index 0000000..3724a2e --- /dev/null +++ b/src/toggle.rs @@ -0,0 +1,30 @@ +#![allow(deprecated)] + +extern crate dbus; +#[macro_use] +extern crate dbus_macros; + +use dbus::{BusType, Connection}; +use std::rc::Rc; + +dbus_interface!("net.ddns.chiocciolo.waydrop.term", interface Term { + fn toggle() -> bool; + fn run_shell(cwd: String, shell: Vec) -> bool; + fn run_in_default_shell(cwd: String, command: String) -> bool; + fn run_in_custom_shell(cwd: String , shell: Vec, command: String) -> bool; +}); + +fn main() { + let session_connection = std::rc::Rc::new(Connection::get_private(BusType::Session).unwrap()); + let term = Term::new( + "net.ddns.chiocciolo.waydrop.term", + "/Term", + session_connection, + ); + // let res = term.run_in_custom_shell( + // vec!["/bin/bash".to_string()], + // "/usr/bin/htop".to_string(), + // ); + //let res = term.run_in_default_shell("/".to_string(), "ls".to_string()); + let _ = term.toggle(); +} diff --git a/src/wake.rs b/src/wake.rs deleted file mode 100644 index b1da613..0000000 --- a/src/wake.rs +++ /dev/null @@ -1,7 +0,0 @@ -use std::os::unix::net::UnixStream; -use std::io::prelude::*; -fn main() -> std::io::Result<()>{ - let mut s = UnixStream::connect("/tmp/waydrop.sock")?; - s.write_all(b"t")?; - Ok(()) -} \ No newline at end of file diff --git a/src/wake_listener.rs b/src/wake_listener.rs index 47e4ce8..f883472 100644 --- a/src/wake_listener.rs +++ b/src/wake_listener.rs @@ -1,23 +1,49 @@ +use dbus_macros::*; use glib::Sender; -pub fn listener(tx: &Sender) { - use std::io::Read; - use std::os::unix::net::UnixListener; - let _a = std::fs::remove_file("/tmp/waydrop.sock"); - let sock = UnixListener::bind("/tmp/waydrop.sock").unwrap(); - for stream in sock.incoming() { - match stream { - Ok(mut stream) => { - let mut buf = [0u8]; - if let Ok(_n) = stream.read_exact(&mut buf) { - let _s = String::from_utf8_lossy(&buf).into_owned(); - tx.send(0).expect("can't send"); - } - } - Err(err) => { - eprintln!("{:?}", err); - } - } +pub enum RpcCommand { + Toggle, + RunShell { + cwd: Option, + shell: Vec, + }, + RunInDefaultShell { + cwd: Option, + command: String, + }, + RunInCustomShell { + cwd: Option, + shell: Vec, + command: String, + }, +} +dbus_class!("net.ddns.chiocciolo.waydrop.term", class Term (tx: Sender) { + fn toggle(&this) -> bool{ + this.tx.send(RpcCommand::Toggle).is_ok() + } + + fn run_shell(&this, cwd: String, shell: Vec) -> bool { + let cwd = if cwd != "" {Some(cwd)} else {None }; + this.tx.send(RpcCommand::RunShell{cwd, shell}).is_ok() } -} \ No newline at end of file + fn run_in_default_shell(&this, cwd: String, command: String) -> bool { + let cwd = if cwd != "" {Some(cwd)} else {None }; + this.tx.send(RpcCommand::RunInDefaultShell{cwd, command}).is_ok() + } + + fn run_in_custom_shell(&this, cwd: String, shell: Vec, command: String) -> bool { + let cwd = if cwd != "" {Some(cwd)} else {None }; + this.tx.send(RpcCommand::RunInCustomShell{cwd, shell, command}).is_ok() + } +}); +pub fn listener(tx: Sender) { + use dbus::{BusType, Connection}; + let session_connection = Connection::get_private(BusType::Session).unwrap(); + let hello = Term::new(tx); + hello.run( + "net.ddns.chiocciolo.waydrop.term", + &session_connection, + "/Term", + ); +} diff --git a/waydrop.desktop b/waydrop.desktop new file mode 100644 index 0000000..26c8893 --- /dev/null +++ b/waydrop.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Name=Waydrop +Exec=/home/pietro/Schifezze/cacca/target/release/waydrop +Icon= +Terminal=false +Type=Application +Categories=GNOME;GTK;System;Utility;TerminalEmulator; +