diff --git a/Cargo.toml b/Cargo.toml index 78131a4..591b2e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,10 +9,12 @@ license = "GPL-3.0" readme = "README.md" [features] -default = ["hack"] +default = [] "hack" = [] [dependencies] +log = "0.4.20" +pretty_env_logger = "0.5.0" eyre = "0.6" thiserror = "1.0" @@ -23,7 +25,7 @@ dirs = "5.0.1" clap = { version = "4.4.6", features = ["derive"] } gtk = "0.18" -gdk = "0.18" +gdk = { version = "0.18" , features = ["v3_24"]} glib = "0.18" pango = { version = "0.18", features = ["v1_50"] } @@ -32,8 +34,13 @@ pango = { version = "0.18", features = ["v1_50"] } zoha-vte = { version = "0.5.0", features = ["v0_50"] } zoha-vte-sys = { version = "0.5.0", features = ["v0_50"] } x11rb = "0.12.0" + +[target.'cfg(target_os = "macos")'.dependencies] +libc = "0.2" +cacao = "0.3.2" + +[target.'cfg(target_os = "linux")'.dependencies] device_query = "1.1.3" dbus = "0.9.7" dbus-crossroads = "0.5.2" -log = "0.4.20" -pretty_env_logger = "0.5.0" + diff --git a/Makefile b/Makefile index da3f936..6c6f68f 100644 --- a/Makefile +++ b/Makefile @@ -1,9 +1,7 @@ .DEFAULT_GOAL = r -# RUST_FLAGS := 'RUSTFLAGS=-Awarnings' -RUST_FLAGS := '' - -export +# RUSTFLAGS := -Awarnings +# export .PHONY: c c: diff --git a/README.md b/README.md index 62742cf..47bf92e 100644 --- a/README.md +++ b/README.md @@ -260,3 +260,4 @@ zoha --dry-run # OR zoha --dry-run -k ``` +atk pango gtk+3 vte3 diff --git a/build.rs b/build.rs new file mode 100644 index 0000000..caa815c --- /dev/null +++ b/build.rs @@ -0,0 +1,6 @@ +fn main() { + if cfg!(target_os = "macos") { + println!("cargo:rustc-link-lib=framework=Carbon"); + println!("cargo:rustc-link-lib=framework=AppKit"); + } +} diff --git a/src/config/args.rs b/src/config/args.rs index 091dee4..9616241 100644 --- a/src/config/args.rs +++ b/src/config/args.rs @@ -9,14 +9,19 @@ pub struct ZohaArgs { /// Disable listening on dbus for keypress. #[arg(short, long, default_value_t = false)] - #[cfg(feature = "hack")] + #[cfg(all(feature = "hack"))] pub keypress_grabber: bool, /// List keys accepted by keypress grabber. #[arg(long, default_value_t = false)] - #[cfg(feature = "hack")] + #[cfg(all(feature = "hack"))] pub list_key_grabber_keys: bool, + /// Enable native key listener. + #[arg(short, long, default_value_t = true)] + #[cfg(all(target_os = "macos"))] + pub listener: bool, + /// Signal Zoha to toggle visibility and exit. #[arg(short, long, default_value_t = false)] pub signal: bool, @@ -40,4 +45,5 @@ pub struct ZohaArgs { /// Print color pallets #[arg(long, default_value_t = false)] pub print_pallets: bool, -} \ No newline at end of file +} + diff --git a/src/config/cfg.rs b/src/config/cfg.rs index 852fc7e..55af6bc 100644 --- a/src/config/cfg.rs +++ b/src/config/cfg.rs @@ -712,6 +712,7 @@ mod defaults { pub(super) const TAB_NUM_CHARS: i8 = 25; // pub(super) const PROMPT_ON_EXIT: bool = false; + #[cfg(feature = "hack")] pub(super) const TOGGLE_KEYCODE: &str = "F1"; pub(super) const ACTION_TAB_ADD: &str = "t"; @@ -737,6 +738,7 @@ mod defaults { pub(super) const ACTION_FONT_SIZE_DEC: &str = "minus"; pub(super) const ACTION_FONT_SIZE_RESET: &str = "0"; + #[cfg(feature = "hack")] pub(super) fn default_key_codes() -> Vec { return TOGGLE_KEYCODE.split('+').map(|it| it.to_string()).collect(); } diff --git a/src/lib.rs b/src/lib.rs index db3864b..5e6e5c8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,14 +1,15 @@ #![allow(clippy::needless_return)] +#[cfg(all(feature = "hack", not(target_os = "linux")))] +compile_error!("feature 'hack' can oly be enabled on linux"); use std::cell::RefCell; use std::collections::HashMap; use std::fmt::Debug; use std::fmt::Formatter; -use std::rc::Rc; +use std::sync::Arc; +use cacao::foundation::id; +use cacao::objc::{class, msg_send, sel, sel_impl}; -use dbus::blocking::Connection; -use dbus::channel::Sender; -use dbus::Message; use eyre::ContextCompat; use eyre::eyre; use gdk::Display; @@ -16,8 +17,10 @@ use gdk::prelude::MonitorExt; use gtk::AccelGroup; use gtk::Application; use gtk::ApplicationWindow; +#[cfg(target_os = "linux")] use gtk::gio::DBusSignalFlags; use gtk::Notebook; +#[cfg(target_os = "linux")] use gtk::prelude::ApplicationExt; use gtk::prelude::ContainerExt; use gtk::prelude::GtkWindowExt; @@ -25,6 +28,13 @@ use gtk::prelude::NotebookExt; use gtk::prelude::WidgetExt; use log::{debug, trace}; +#[cfg(target_os = "linux")] +use dbus::blocking::Connection; +#[cfg(target_os = "linux")] +use dbus::channel::Sender; +#[cfg(target_os = "linux")] +use dbus::Message; + use crate::config::cfg::ZohaCfg; use crate::config::color::Pallet; use crate::ui::actions::set_app_actions; @@ -42,21 +52,24 @@ pub mod ui; pub mod hack; +#[cfg(target_os = "linux")] pub const DBUS_INTERFACE: &str = "io.koosha.zoha"; +#[cfg(target_os = "linux")] pub const DBUS_MEMBER: &str = "zoha"; +#[cfg(target_os = "linux")] pub const DBUS_PATH: &str = "/io/koosha/zoha"; struct TabCounter(usize); pub struct ZohaCtx { - pub cfg: Rc, + pub cfg: Arc, pub font_scale: f64, pub fullscreen: bool, pub accel_group: AccelGroup, pub showing: bool, - pub terminals: Rc>>, + pub terminals: Arc>>, pub transparency_enabled: bool, - tab_counter: Rc>, + tab_counter: Arc>, window: Option, notebook: Option, } @@ -79,7 +92,7 @@ impl Debug for ZohaCtx { } impl ZohaCtx { - pub fn new(cfg: Rc) -> Self { + pub fn new(cfg: Arc) -> Self { let fullscreen = cfg.display.fullscreen; return Self { cfg, @@ -87,11 +100,11 @@ impl ZohaCtx { fullscreen, accel_group: AccelGroup::new(), showing: true, - terminals: Rc::new(RefCell::new(HashMap::new())), + terminals: Arc::new(RefCell::new(HashMap::new())), transparency_enabled: true, window: None, notebook: None, - tab_counter: Rc::new(RefCell::new(TabCounter(1))), + tab_counter: Arc::new(RefCell::new(TabCounter(1))), }; } @@ -155,11 +168,11 @@ impl ZohaCtx { } -pub fn on_app_activate(ctx: &Rc>, +pub fn on_app_activate(ctx: &Arc>, app: &Application) -> eyre::Result<()> { let window: ApplicationWindow = create_window(&ctx.borrow().cfg, app).build(); - // let ctx_on_focus = Rc::clone(ctx); + // let ctx_on_focus = Arc::clone(ctx); // window.connect_activate_focus(move |_| { // match ctx_on_focus.borrow().get_notebook() { // None => eprintln!("missing notebook on window activate"), @@ -194,7 +207,7 @@ pub fn on_app_activate(ctx: &Rc>, add_tab(ctx, !ctx.borrow().cfg.display.start_hidden); - let reorder_ctx = Rc::clone(ctx); + let reorder_ctx = Arc::clone(ctx); ctx.borrow().get_notebook().unwrap().connect_page_reordered(move |_, child, index| { on_page_reorder(&reorder_ctx, child, index); }); @@ -211,10 +224,11 @@ pub fn on_app_activate(ctx: &Rc>, return Ok(()); } -pub fn connect_gdk_dbus(ctx: &Rc>, +#[cfg(target_os = "linux")] +pub fn connect_gdk_dbus(ctx: &Arc>, app: &Application) { let app: Application = app.clone(); - let ctx = Rc::clone(ctx); + let ctx = Arc::clone(ctx); app.dbus_connection() .expect("could not get a dbus connection") .signal_subscribe( @@ -230,7 +244,7 @@ pub fn connect_gdk_dbus(ctx: &Rc>, ); } -pub fn toggle(ctx: &Rc>) { +pub fn toggle(ctx: &Arc>) { let mut ctx = ctx.borrow_mut(); let window: &ApplicationWindow = ctx @@ -244,9 +258,11 @@ pub fn toggle(ctx: &Rc>) { window.show_all(); window.present(); ctx.showing = true; + unsafe { macos_screens(); } } } +#[cfg(target_os = "linux")] pub fn send_toggle_signal_through_dbus() -> eyre::Result<()> { debug!("sending dbus signal"); let conn: Connection = Connection::new_session()?; @@ -257,8 +273,10 @@ pub fn send_toggle_signal_through_dbus() -> eyre::Result<()> { } Err(_) => Err(eyre!("failed to send dbus signal")), }; + return Ok(()); } +#[cfg(target_os = "linux")] pub(crate) fn new_signal() -> Message { let signal = Message::new_signal( DBUS_PATH, @@ -287,7 +305,7 @@ pub fn list_monitors() -> eyre::Result> { return Ok(monitors); } -#[cfg(feature = "hack")] +#[cfg(all(feature = "hack"))] pub fn list_keycodes() -> Vec<&'static str> { return vec![ "Key0", @@ -588,4 +606,26 @@ pub fn print_pallets() { println!("[13] = {}", pallet.colors()[13]); println!("[14] = {}", pallet.colors()[14]); } -} \ No newline at end of file +} + +pub unsafe fn macos_screens() { + // NSWindowCollectionBehaviorCanJoinAllSpaces and friends + let mask = 1 | (1 << 6) | (1 << 8); + + let shared: id = msg_send![class!(NSApplication), sharedApplication]; + println!("shared {:?}", shared); + + let windows: id = msg_send![shared, windows]; + println!("windows {:?}", windows); + + let window: id = msg_send![windows, firstObject]; + println!("first {:?}", window); + + if !window.is_null() { + let _: () = msg_send![window, setCollectionBehavior:mask]; + } + else { + eprintln!("no window") + } +} + diff --git a/src/main.rs b/src/main.rs index eded45f..776fe07 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,35 +1,42 @@ #![allow(clippy::needless_return)] use std::cell::RefCell; -use std::env; -use std::rc::Rc; +use std::sync::Arc; use clap::Parser; use eyre::Result; use gtk::Application; use gtk::prelude::ApplicationExt; use gtk::prelude::ApplicationExtManual; -use log::debug; +use log::{debug, trace}; use config::cfg::read_cfg_content; use zoha::{config, print_config, print_pallets}; use zoha::config::args::ZohaArgs; +use zoha::config::cfg::read_cfg_content; use zoha::config::cfg::ZohaCfg; +#[cfg(target_os = "linux")] use zoha::connect_gdk_dbus; #[cfg(feature = "hack")] use zoha::hack::enable_key_grabber_hack; +#[cfg(target_os = "linux")] use zoha::list_keycodes; use zoha::list_monitors; use zoha::on_app_activate; +#[cfg(target_os = "linux")] use zoha::send_toggle_signal_through_dbus; use zoha::ui::window::create_application; use zoha::ZohaCtx; +#[cfg(target_os = "macos")] +static mut CTX: Option>> = None; + fn main() -> Result<()> { pretty_env_logger::init(); let args: ZohaArgs = ZohaArgs::parse(); + #[cfg(target_os = "linux")] if args.signal { send_toggle_signal_through_dbus()?; return Ok(()); @@ -95,11 +102,11 @@ fn main() -> Result<()> { return Ok(()); } - let cfg: Rc = Rc::new(cfg); + let cfg: Arc = Arc::new(cfg); let ctx: ZohaCtx = ZohaCtx::new(cfg); - let ctx = Rc::new(RefCell::new(ctx)); - let ctx0 = Rc::clone(&ctx); + let ctx = Arc::new(RefCell::new(ctx)); + let ctx0 = Arc::clone(&ctx); #[cfg(feature = "hack")] let _guard = @@ -129,12 +136,175 @@ fn main() -> Result<()> { application.connect_activate(move |app| { match on_app_activate(&ctx0, app) { - Ok(_) => connect_gdk_dbus(&ctx0, app), + Ok(_) => { + #[cfg(target_os = "linux")] + connect_gdk_dbus(&ctx0, app) + } Err(err) => eprintln!("{}", err), } }); + unsafe { + #[cfg(target_os = "macos")] + if args.listener { + debug!("enabling native key listener"); + CTX = Some(Arc::clone(&ctx)); + mac_hacks::macos_key_grabber(); + mac_hacks::macos_window(); + } else { + trace!("not enabling native key listener"); + CTX = None; + } + } + application.run_with_args::(&[]); return Ok(()); } + +#[cfg(target_os = "macos")] +mod mac_hacks { + use std::ffi::c_void; + use std::ptr; + + use cacao::appkit::{App, AppDelegate}; + use cacao::foundation::YES; + use cacao::objc::{class, msg_send, sel, sel_impl}; + use libc::c_int; + + use zoha::{macos_screens, toggle}; + + #[repr(C)] + struct EventTypeSpec { + event_class: u32, + event_kind: u32, + } + + #[repr(C)] + struct EventHotKeyID { + signature: c_int, + id: u32, + } + + #[repr(C)] + struct OpaqueCStruct8Hack { + _private: [u8; 8], + } + + #[repr(C)] + struct OpaqueCStructBigHack { + _private: [u8; 1024], + } + + impl OpaqueCStructBigHack { + fn new() -> OpaqueCStructBigHack { + Self { + _private: [0; 1024], + } + } + } + + type Handler = extern "C" fn( + *const c_void, + *const c_void, + *const c_void, + ) -> c_int; + + extern "C" { + fn GetApplicationEventTarget() -> OpaqueCStruct8Hack; + + fn InstallEventHandler( + event_target: OpaqueCStruct8Hack, + handler: Handler, + num_events: libc::c_ulong, + event_type_spec: *const EventTypeSpec, + user_data: *const c_void, + out_ref: *mut c_void, + ) -> c_int; + + fn RegisterEventHotKey( + key_code: u32, + modifiers: u32, + hotkey_id: EventHotKeyID, + target: OpaqueCStruct8Hack, + options: u32, + event_hotkey_ref: *mut OpaqueCStructBigHack, + ) -> c_int; + } + + extern "C" fn handler( + _next_handler: *const c_void, + _event_ref: *const c_void, + _user_data: *const c_void, + ) -> c_int { + println!("got something"); + unsafe { + if let Some(ctx) = super::CTX.as_ref() { + toggle(ctx); + } else { + eprint!("missing context on toggle"); + } + + macos_screens(); + } + return 0; + } + + pub unsafe fn macos_key_grabber() { + let event_type_spec = EventTypeSpec { + // kEventClassKeyboard + event_class: 1801812322, + + // kEventHotKeyReleased + event_kind: 6, + }; + + let result = InstallEventHandler( + GetApplicationEventTarget(), + handler, + 1, + &event_type_spec, + ptr::null(), + ptr::null_mut(), + ); + + if result != 0 { + panic!("failed to install event handler"); + } + + let key_id = EventHotKeyID { + signature: 1, + id: 1, + }; + + let result = RegisterEventHotKey( + 0x6D, // F10 + 256, // cmd + key_id, + GetApplicationEventTarget(), + 0, + &mut OpaqueCStructBigHack::new(), + ); + + if result != 0 { + panic!("failed to register event hot key"); + } + } + + #[derive(Default)] + struct ZohaApp; + + impl AppDelegate for ZohaApp {} + + pub unsafe fn macos_window() { + let mut app: App = App::new( + "io.koosha.zoha", + ZohaApp::default(), + ); + + let _: () = msg_send![app.objc, activateIgnoringOtherApps: YES]; + + macos_screens(); + } + +} diff --git a/src/ui/actions.rs b/src/ui/actions.rs index 614b50e..98b71d5 100644 --- a/src/ui/actions.rs +++ b/src/ui/actions.rs @@ -1,5 +1,5 @@ use std::cell::RefCell; -use std::rc::Rc; +use std::sync::Arc; use gdk::gio::Action; use glib::clone; @@ -214,7 +214,7 @@ pub fn set_app_actions(ctx: &ZohaCtx, } } -pub fn set_win_actions(ctx: &Rc>) { +pub fn set_win_actions(ctx: &Arc>) { let cxb = ctx.borrow(); let window: &ApplicationWindow = cxb.get_window().unwrap(); @@ -236,7 +236,7 @@ pub fn set_win_actions(ctx: &Rc>) { if let Some(key) = cxb.cfg.keys.tab_add.as_ref() { let sa = SimpleAction::new(ACTION__ZOHA__TAB_ADD, None); - let ctx = Rc::clone(ctx); + let ctx = Arc::clone(ctx); sa.connect_activate(move |_, _| { add_tab(&ctx, true); }); @@ -249,7 +249,7 @@ pub fn set_win_actions(ctx: &Rc>) { if let Some(key) = cxb.cfg.keys.tab_close.as_ref() { let sa = SimpleAction::new(ACTION__ZOHA__TAB_CLOSE, None); - let ctx = Rc::clone(ctx); + let ctx = Arc::clone(ctx); sa.connect_activate(move |_, _| { close_tab(&ctx); }); @@ -262,7 +262,7 @@ pub fn set_win_actions(ctx: &Rc>) { if let Some(key) = cxb.cfg.keys.tab_move_backward.as_ref() { let sa = SimpleAction::new(ACTION__ZOHA__TAB_MOVE_BACKWARD, None); - let ctx = Rc::clone(ctx); + let ctx = Arc::clone(ctx); sa.connect_activate(move |_, _| { move_backward(&ctx); }); @@ -275,7 +275,7 @@ pub fn set_win_actions(ctx: &Rc>) { if let Some(key) = cxb.cfg.keys.tab_move_forward.as_ref() { let sa = SimpleAction::new(ACTION__ZOHA__TAB_MOVE_FORWARD, None); - let ctx = Rc::clone(ctx); + let ctx = Arc::clone(ctx); sa.connect_activate(move |_, _| { move_forward(&ctx); }); @@ -288,7 +288,7 @@ pub fn set_win_actions(ctx: &Rc>) { if let Some(key) = cxb.cfg.keys.tab_goto_next.as_ref() { let sa = SimpleAction::new(ACTION__ZOHA__TAB_GOTO_NEXT, None); - let ctx = Rc::clone(ctx); + let ctx = Arc::clone(ctx); sa.connect_activate(move |_, _| { goto_next(&ctx); }); @@ -301,7 +301,7 @@ pub fn set_win_actions(ctx: &Rc>) { if let Some(key) = cxb.cfg.keys.tab_goto_previous.as_ref() { let sa = SimpleAction::new(ACTION__ZOHA__TAB_GOTO_PREVIOUS, None); - let ctx = Rc::clone(ctx); + let ctx = Arc::clone(ctx); sa.connect_activate(move |_, _| { goto_previous(&ctx); }); @@ -314,7 +314,7 @@ pub fn set_win_actions(ctx: &Rc>) { if let Some(key) = cxb.cfg.keys.tab_goto_last.as_ref() { let sa = SimpleAction::new(ACTION__ZOHA__TAB_GOTO_LAST, None); - let ctx = Rc::clone(ctx); + let ctx = Arc::clone(ctx); sa.connect_activate(move |_, _| { goto_last(&ctx); }); @@ -327,7 +327,7 @@ pub fn set_win_actions(ctx: &Rc>) { if let Some(key) = cxb.cfg.keys.tab_goto_01.as_ref() { let sa = SimpleAction::new(ACTION__ZOHA__TAB_GOTO_01, None); - let ctx = Rc::clone(ctx); + let ctx = Arc::clone(ctx); sa.connect_activate(move |_, _| { goto_n(&ctx, 1); }); @@ -340,7 +340,7 @@ pub fn set_win_actions(ctx: &Rc>) { if let Some(key) = cxb.cfg.keys.tab_goto_02.as_ref() { let sa = SimpleAction::new(ACTION__ZOHA__TAB_GOTO_02, None); - let ctx = Rc::clone(ctx); + let ctx = Arc::clone(ctx); sa.connect_activate(move |_, _| { goto_n(&ctx, 2); }); @@ -353,7 +353,7 @@ pub fn set_win_actions(ctx: &Rc>) { if let Some(key) = cxb.cfg.keys.tab_goto_03.as_ref() { let sa = SimpleAction::new(ACTION__ZOHA__TAB_GOTO_03, None); - let ctx = Rc::clone(ctx); + let ctx = Arc::clone(ctx); sa.connect_activate(move |_, _| { goto_n(&ctx, 3); }); @@ -366,7 +366,7 @@ pub fn set_win_actions(ctx: &Rc>) { if let Some(key) = cxb.cfg.keys.tab_goto_04.as_ref() { let sa = SimpleAction::new(ACTION__ZOHA__TAB_GOTO_04, None); - let ctx = Rc::clone(ctx); + let ctx = Arc::clone(ctx); sa.connect_activate(move |_, _| { goto_n(&ctx, 4); }); @@ -379,7 +379,7 @@ pub fn set_win_actions(ctx: &Rc>) { if let Some(key) = cxb.cfg.keys.tab_goto_05.as_ref() { let sa = SimpleAction::new(ACTION__ZOHA__TAB_GOTO_05, None); - let ctx = Rc::clone(ctx); + let ctx = Arc::clone(ctx); sa.connect_activate(move |_, _| { goto_n(&ctx, 5); }); @@ -392,7 +392,7 @@ pub fn set_win_actions(ctx: &Rc>) { if let Some(key) = cxb.cfg.keys.tab_goto_06.as_ref() { let sa = SimpleAction::new(ACTION__ZOHA__TAB_GOTO_06, None); - let ctx = Rc::clone(ctx); + let ctx = Arc::clone(ctx); sa.connect_activate(move |_, _| { goto_n(&ctx, 6); }); @@ -405,7 +405,7 @@ pub fn set_win_actions(ctx: &Rc>) { if let Some(key) = cxb.cfg.keys.tab_goto_07.as_ref() { let sa = SimpleAction::new(ACTION__ZOHA__TAB_GOTO_07, None); - let ctx = Rc::clone(ctx); + let ctx = Arc::clone(ctx); sa.connect_activate(move |_, _| { goto_n(&ctx, 7); }); @@ -418,7 +418,7 @@ pub fn set_win_actions(ctx: &Rc>) { if let Some(key) = cxb.cfg.keys.tab_goto_08.as_ref() { let sa = SimpleAction::new(ACTION__ZOHA__TAB_GOTO_08, None); - let ctx = Rc::clone(ctx); + let ctx = Arc::clone(ctx); sa.connect_activate(move |_, _| { goto_n(&ctx, 8); }); @@ -433,7 +433,7 @@ pub fn set_win_actions(ctx: &Rc>) { if let Some(key) = cxb.cfg.keys.copy.as_ref() { let sa = SimpleAction::new(ACTION__ZOHA__COPY, None); - let ctx = Rc::clone(ctx); + let ctx = Arc::clone(ctx); sa.connect_activate(move |_, _| { copy(&ctx); }); @@ -446,7 +446,7 @@ pub fn set_win_actions(ctx: &Rc>) { if let Some(key) = cxb.cfg.keys.paste.as_ref() { let sa = SimpleAction::new(ACTION__ZOHA__PASTE, None); - let ctx = Rc::clone(ctx); + let ctx = Arc::clone(ctx); sa.connect_activate(move |_, _| { paste(&ctx); }); @@ -462,7 +462,7 @@ pub fn set_win_actions(ctx: &Rc>) { if let Some(key) = cxb.cfg.keys.transparency_toggle.as_ref() { let sa = SimpleAction::new(ACTION__ZOHA__TRANSPARENCY_TOGGLE, None); - let ctx = Rc::clone(ctx); + let ctx = Arc::clone(ctx); sa.connect_activate(move |_, _| { toggle_transparency(&ctx); }); @@ -477,7 +477,7 @@ pub fn set_win_actions(ctx: &Rc>) { if let Some(key) = cxb.cfg.keys.font_size_inc.as_ref() { let sa = SimpleAction::new(ACTION__ZOHA__FONT_INC, None); - let ctx = Rc::clone(ctx); + let ctx = Arc::clone(ctx); sa.connect_activate(move |_, _| { font_inc(&ctx); }); @@ -490,7 +490,7 @@ pub fn set_win_actions(ctx: &Rc>) { if let Some(key) = cxb.cfg.keys.font_size_dec.as_ref() { let sa = SimpleAction::new(ACTION__ZOHA__FONT_DEC, None); - let ctx = Rc::clone(ctx); + let ctx = Arc::clone(ctx); sa.connect_activate(move |_, _| { font_dec(&ctx); }); @@ -503,7 +503,7 @@ pub fn set_win_actions(ctx: &Rc>) { if let Some(key) = cxb.cfg.keys.font_size_reset.as_ref() { let sa = SimpleAction::new(ACTION__ZOHA__FONT_RESET, None); - let ctx = Rc::clone(ctx); + let ctx = Arc::clone(ctx); sa.connect_activate(move |_, _| { font_reset(&ctx); }); diff --git a/src/ui/terminal.rs b/src/ui/terminal.rs index 02b5bdf..b010896 100644 --- a/src/ui/terminal.rs +++ b/src/ui/terminal.rs @@ -4,7 +4,7 @@ use std::fmt::Formatter; use std::fs; use std::path::Path; use std::path::PathBuf; -use std::rc::Rc; +use std::sync::Arc; use std::string::ToString; use gdk::gio; @@ -30,7 +30,7 @@ use crate::ui::window::remove_page_by_hbox; use crate::ZohaCtx; struct ZohaTerminalCtx { - ctx: Rc>, + ctx: Arc>, pid: Option, // dropped_to_default_shell: bool, // working_dir: Option, @@ -45,7 +45,7 @@ pub struct ZohaTerminal { pub vte: Terminal, pub scrollbar: Scrollbar, pub tab_counter: usize, - ctx: Rc>, + ctx: Arc>, } impl Debug for ZohaTerminal { @@ -62,7 +62,7 @@ impl Debug for ZohaTerminal { } impl ZohaTerminal { - pub fn new(ctx: Rc>) -> Self { + pub fn new(ctx: Arc>) -> Self { let vte: Terminal = { let cfg = &ctx.borrow().cfg; @@ -130,7 +130,7 @@ impl ZohaTerminal { // .as_ref() // .map(|it| it.to_string()); - let term_ctx = Rc::new(RefCell::new(ZohaTerminalCtx { + let term_ctx = Arc::new(RefCell::new(ZohaTerminalCtx { ctx, pid: None, // dropped_to_default_shell: false, @@ -149,8 +149,8 @@ impl ZohaTerminal { } pub fn connect_signals(&self) { - let ctx = Rc::clone(&self.ctx); - let ctx0 = Rc::clone(&ctx); + let ctx = Arc::clone(&self.ctx); + let ctx0 = Arc::clone(&ctx); let handler: SignalHandlerId = self.vte.connect_child_exited(move |vte, _| { let mut cxb = ctx.borrow_mut(); diff --git a/src/ui/window.rs b/src/ui/window.rs index 822f046..a8c02be 100644 --- a/src/ui/window.rs +++ b/src/ui/window.rs @@ -1,8 +1,9 @@ use std::cell::RefCell; use std::collections::HashMap; -use std::rc::Rc; +use std::sync::Arc; -use gdk::EventMask; +use gdk::{EventMask, FullscreenMode}; +use gdk::prelude::WindowExtManual; use glib::Cast; use gtk::Application; use gtk::ApplicationWindow; @@ -142,7 +143,7 @@ pub fn create_notebook(ctx: &mut ZohaCtx) { } } -pub fn on_page_reorder(ctx: &Rc>, +pub fn on_page_reorder(ctx: &Arc>, child: &Widget, new_position: u32) { let child = match child.downcast_ref::() { @@ -192,7 +193,7 @@ pub fn on_page_reorder(ctx: &Rc>, ctx.borrow().terminals.borrow_mut().extend(new_order); } -pub fn on_page_removed(ctx: &Rc>, +pub fn on_page_removed(ctx: &Arc>, page: u32) { debug!("page removed: {}", page); @@ -218,7 +219,7 @@ pub fn on_page_removed(ctx: &Rc>, terminals.extend(adjusted); } -pub fn remove_page_by_hbox(ctx: &Rc>, +pub fn remove_page_by_hbox(ctx: &Arc>, hbox: >k::Box) { let page: Option = match ctx.borrow().get_notebook() { None => { @@ -254,11 +255,11 @@ pub fn remove_page_by_hbox(ctx: &Rc>, } } -pub fn add_tab(ctx: &Rc>, +pub fn add_tab(ctx: &Arc>, grab_focus: bool) { trace!("tab_add, focus: {}", grab_focus); - let term = ZohaTerminal::new(Rc::clone(ctx)); + let term = ZohaTerminal::new(Arc::clone(ctx)); let (idx, dir) = match ctx.borrow().get_notebook() { None => { @@ -340,7 +341,7 @@ pub fn add_tab(ctx: &Rc>, } } -pub fn close_tab(ctx: &Rc>) { +pub fn close_tab(ctx: &Arc>) { trace!("clos_tab"); if let Some(mut term) = get_term(ctx, "close_tab") { @@ -348,15 +349,15 @@ pub fn close_tab(ctx: &Rc>) { } } -pub fn move_backward(ctx: &Rc>) { +pub fn move_backward(ctx: &Arc>) { move_tab(ctx, false); } -pub fn move_forward(ctx: &Rc>) { +pub fn move_forward(ctx: &Arc>) { move_tab(ctx, true); } -pub fn move_tab(ctx: &Rc>, +pub fn move_tab(ctx: &Arc>, fwd: bool) { trace!("move tab, fwd: {}", fwd); @@ -399,7 +400,7 @@ pub fn move_tab(ctx: &Rc>, ctx.borrow().get_notebook().unwrap().reorder_child(&page, Some(new_index)); } -pub fn goto_next(ctx: &Rc>) { +pub fn goto_next(ctx: &Arc>) { trace!("goto_next"); match ctx.borrow().get_notebook() { @@ -410,7 +411,7 @@ pub fn goto_next(ctx: &Rc>) { } } -pub fn goto_previous(ctx: &Rc>) { +pub fn goto_previous(ctx: &Arc>) { trace!("goto_previous"); match ctx.borrow().get_notebook() { @@ -421,7 +422,7 @@ pub fn goto_previous(ctx: &Rc>) { } } -pub fn goto_last(ctx: &Rc>) { +pub fn goto_last(ctx: &Arc>) { trace!("goto_last"); match ctx.borrow().get_notebook() { @@ -433,7 +434,7 @@ pub fn goto_last(ctx: &Rc>) { } } -pub fn goto_n(ctx: &Rc>, +pub fn goto_n(ctx: &Arc>, n: usize) { trace!("goto_n: {}", n); @@ -447,7 +448,7 @@ pub fn goto_n(ctx: &Rc>, } } -pub fn adjust_tab_bar(ctx: &Rc>) { +pub fn adjust_tab_bar(ctx: &Arc>) { match ctx.borrow().get_notebook() { None => eprintln!("missing notebook on adjust tabs"), Some(notebook) => { @@ -487,7 +488,7 @@ pub fn adjust_tab_bar(ctx: &Rc>) { }; } -pub fn copy(ctx: &Rc>) { +pub fn copy(ctx: &Arc>) { trace!("copy"); if let Some(zt) = get_term(ctx, "copy") { @@ -495,7 +496,7 @@ pub fn copy(ctx: &Rc>) { } } -pub fn paste(ctx: &Rc>) { +pub fn paste(ctx: &Arc>) { trace!("paste"); if let Some(zt) = get_term(ctx, "paste") { @@ -503,7 +504,7 @@ pub fn paste(ctx: &Rc>) { }; } -pub fn toggle_transparency(ctx: &Rc>) { +pub fn toggle_transparency(ctx: &Arc>) { let en = ctx.borrow().transparency_enabled; ctx.borrow_mut().transparency_enabled = !en; @@ -519,7 +520,7 @@ pub fn toggle_transparency(ctx: &Rc>) { }); } -pub fn font_inc(ctx: &Rc>) { +pub fn font_inc(ctx: &Arc>) { trace!("font_inc"); ctx @@ -536,7 +537,7 @@ pub fn font_inc(ctx: &Rc>) { }); } -pub fn font_dec(ctx: &Rc>) { +pub fn font_dec(ctx: &Arc>) { trace!("font_dec"); ctx @@ -553,7 +554,7 @@ pub fn font_dec(ctx: &Rc>) { }); } -pub fn font_reset(ctx: &Rc>) { +pub fn font_reset(ctx: &Arc>) { trace!("font_reset"); ctx @@ -570,7 +571,7 @@ pub fn font_reset(ctx: &Rc>) { }); } -fn get_term(ctx: &Rc>, +fn get_term(ctx: &Arc>, action: &'_ str) -> Option { let active_page: u32 = match ctx .borrow() @@ -602,7 +603,7 @@ fn get_term(ctx: &Rc>, return term; } -fn set_label(ctx: &Rc>, +fn set_label(ctx: &Arc>, term: &ZohaTerminal, idx: u32) { trace!("set_label, idx={}", idx);