/* waydrop - a drop-down terminal for wayland * * Copyright 2021 Pietro Brenna * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 3 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library. If not, see . */ use gtk::gio; use gtk::glib; use gio::prelude::*; use gtk::prelude::*; use glib::clone; // use gtk4::SettingsExt; use std::env::args; use std::thread; mod menu; mod tabs; mod wake_listener; mod window_state; use crate::vte::TerminalExt; use window_state::{FullScreenState, StateOperations, WindowPos, WindowState}; fn build_ui(application: >k::Application) { let window = gtk::ApplicationWindow::new(application); window.settings().set_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(Some("Waydrop")); // window.border().set_left(0);ò let surf = window.surface(); // 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, 700); window.set_decorated(false); window.set_can_focus(true); window.set_keep_above(true); let nb = gtk::Notebook::new(); 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(); 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::open_tab(&window, &nb, true, None, None, None, &w_state6); true }), ); let a = gtk::accelerator_parse("Page_Down"); let b = gtk::accelerator_parse("plus"); for (key, modifier) in &[a, b] { 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 a = gtk::accelerator_parse("Page_Up"); let b = gtk::accelerator_parse("egrave"); for (key, modifier) in &[a, b] { 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("c"); accel_group.connect_accel_group( key, modifier, gtk::AccelFlags::VISIBLE, clone!(@weak nb => @default-return true, move |_accel_g, _window, _key, _modif| { let p_num = nb.get_current_page(); let page = nb.get_nth_page(p_num); if let Some(vte) = page { let _ = vte.downcast::().map(|x| if x.get_has_selection() { x.emit_copy_clipboard() }); } true }), ); let (key, modifier) = gtk::accelerator_parse("v"); accel_group.connect_accel_group( key, modifier, gtk::AccelFlags::VISIBLE, clone!(@weak nb => @default-return true, move |_accel_g, _window, _key, _modif| { let p_num = nb.get_current_page(); let page = nb.get_nth_page(p_num); if let Some(vte) = page { let _ = vte.downcast::().map(|x| x.paste_clipboard()); } true }), ); let (key, modifier) = gtk::accelerator_parse("F11"); accel_group.connect_accel_group( key, modifier, gtk::AccelFlags::VISIBLE, clone!(@weak window => @default-return true, move |_accel_g, _win, _key, _modif| { match w_state4.get_full() { FullScreenState::Full => { window.unfullscreen(); w_state4.set_full(FullScreenState::NotFull); } FullScreenState::NotFull => { window.fullscreen(); w_state4.set_full(FullScreenState::Full); } _ => {} } 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); 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); window.set_skip_pager_hint(true); window.show_all(); window.hide(); /*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(), ); }*/ window.connect_focus_out_event(move |_widget, _b| window_state::focus_out(&w_state1)); window.connect_focus_in_event(clone!(@weak window => @default-return gtk::Inhibit(false), move |_widget, _b| window_state::focus_in(&window, &w_state2))); nb.connect_destroy(move |_nb| { w_state.set_pos(WindowPos::Closing); }); 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, &w_state5); window_state::hide(&window, &w_state0); } } else { tabs::set_titles(¬ebook); if notebook.get_n_pages() == 1 { notebook.set_show_tabs(true); } } })); 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); //window_state::bring_up(&window, &w_state4, gtk::get_current_event_time()); //tabs::focus_tab_corrente(&nb); rx.attach(None, move |cmd| { let tira_su = || { window_state::bring_up(&window, &w_state3, gtk4::get_current_event_time()); }; use wake_listener::RpcCommand::*; match cmd { Toggle => { window_state::esegui_toggle(&window, &nb, &w_state3); } NewShell { cwd } => { tira_su(); tabs::open_tab(&window, &nb, true, cwd, None, None, &w_state7); } RunShell { cwd, shell } => { tira_su(); 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), &w_state7); } RunInCustomShell { cwd, shell, command, } => { tira_su(); tabs::open_tab(&window, &nb, true, cwd, Some(shell), Some(command), &w_state7); } } glib::Continue(true) }); thread::spawn(move || { if let Err(e) = wake_listener::listener(tx) { eprintln!("Could not listen on dbus: {}", e); } }); } fn main() { let application = gtk::Application::new(Some("net.ddns.chiocciolo.waydrop"), Default::default()) .expect("Initialization failed..."); application.connect_activate(|app| { build_ui(app); }); application.run(&args().collect::>()); }