diff --git a/src/cmd_line.rs b/src/cmd_line.rs index 59fe8b7..adee7be 100644 --- a/src/cmd_line.rs +++ b/src/cmd_line.rs @@ -1,4 +1,4 @@ -use crate::{dimensions::Dimensions, settings::*}; +use crate::{dimensions::Dimensions, frame::Frame, settings::*}; use clap::{App, Arg}; @@ -13,7 +13,7 @@ pub struct CmdLineSettings { pub remote_tcp: Option, pub wsl: bool, // Command-line flags with environment variable fallback - pub frameless: bool, + pub frame: Frame, pub maximized: bool, pub multi_grid: bool, pub no_idle: bool, @@ -36,7 +36,7 @@ impl Default for CmdLineSettings { remote_tcp: None, wsl: false, // Command-line flags with environment variable fallback - frameless: false, + frame: Frame::Full, maximized: false, multi_grid: false, no_idle: false, @@ -98,9 +98,10 @@ pub fn handle_command_line_arguments(args: Vec) -> Result<(), String> { ) // Command-line flags with environment variable fallback .arg( - Arg::with_name("frameless") - .long("frameless") - .help("Removes the window frame. NOTE: Window might not be resizable after this setting is enabled.") + Arg::with_name("frame") + .long("frame") + .takes_value(true) + .help("Configure the window frame. NOTE: Window might not be resizable if setting is None.") ) .arg( Arg::with_name("maximized") @@ -169,7 +170,13 @@ pub fn handle_command_line_arguments(args: Vec) -> Result<(), String> { remote_tcp: matches.value_of("remote_tcp").map(|i| i.to_owned()), wsl: matches.is_present("wsl"), // Command-line flags with environment variable fallback - frameless: matches.is_present("frameless") || std::env::var("NEOVIDE_FRAMELESS").is_ok(), + frame: match matches.value_of("frame") { + Some(val) => Frame::from_string(val.to_string()), + None => match std::env::var("NEOVIDE_FRAME") { + Ok(f) => Frame::from_string(f), + Err(_) => Frame::Full, + }, + }, maximized: matches.is_present("maximized") || std::env::var("NEOVIDE_MAXIMIZED").is_ok(), multi_grid: matches.is_present("multi_grid") || std::env::var("NEOVIDE_MULTIGRID").is_ok(), no_idle: matches.is_present("noidle") || std::env::var("NEOVIDE_NO_IDLE").is_ok(), @@ -308,14 +315,14 @@ mod tests { #[test] fn test_frameless_flag() { - let args: Vec = vec!["neovide", "--frameless"] + let args: Vec = vec!["neovide", "--frame=full"] .iter() .map(|s| s.to_string()) .collect(); let _accessing_settings = ACCESSING_SETTINGS.lock().unwrap(); handle_command_line_arguments(args).expect("Could not parse arguments"); - assert_eq!(SETTINGS.get::().frameless, true); + assert_eq!(SETTINGS.get::().frame, Frame::Full); } #[test] @@ -323,9 +330,9 @@ mod tests { let args: Vec = vec!["neovide"].iter().map(|s| s.to_string()).collect(); let _accessing_settings = ACCESSING_SETTINGS.lock().unwrap(); - set_var("NEOVIDE_FRAMELESS", "true"); + set_var("NEOVIDE_FRAME", "none"); handle_command_line_arguments(args).expect("Could not parse arguments"); - assert_eq!(SETTINGS.get::().frameless, true); + assert_eq!(SETTINGS.get::().frame, Frame::None); } #[test] diff --git a/src/frame.rs b/src/frame.rs new file mode 100644 index 0000000..aced071 --- /dev/null +++ b/src/frame.rs @@ -0,0 +1,30 @@ +// Options for the frame decorations +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Frame { + Full, + #[cfg(target_os = "macos")] + Transparent, + #[cfg(target_os = "macos")] + Buttonless, + None, +} + +impl Default for Frame { + fn default() -> Frame { + Frame::Full + } +} + +impl Frame { + pub fn from_string(decoration: String) -> Frame { + match decoration.to_lowercase().as_str() { + "full" => Frame::Full, + #[cfg(target_os = "macos")] + "transparent" => Frame::Transparent, + #[cfg(target_os = "macos")] + "buttonless" => Frame::Buttonless, + "none" => Frame::None, + _ => Frame::Full, + } + } +} diff --git a/src/main.rs b/src/main.rs index 783973e..389fed2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,6 +16,7 @@ mod dimensions; mod editor; mod error_handling; mod event_aggregator; +mod frame; mod redraw_scheduler; mod renderer; mod running_tracker; diff --git a/src/window/mod.rs b/src/window/mod.rs index 5d19c57..b79c764 100644 --- a/src/window/mod.rs +++ b/src/window/mod.rs @@ -16,6 +16,9 @@ use glutin::{ use log::trace; use tokio::sync::mpsc::UnboundedReceiver; +#[cfg(target_os = "macos")] +use glutin::platform::macos::WindowBuilderExtMacOS; + #[cfg(target_os = "linux")] use glutin::platform::unix::WindowBuilderExtUnix; @@ -30,6 +33,7 @@ use crate::{ dimensions::Dimensions, editor::EditorCommand, event_aggregator::EVENT_AGGREGATOR, + frame::Frame, redraw_scheduler::REDRAW_SCHEDULER, renderer::Renderer, running_tracker::*, @@ -275,12 +279,34 @@ pub fn create_window() { } } - let mut winit_window_builder = window::WindowBuilder::new() + let winit_window_builder = window::WindowBuilder::new() .with_title("Neovide") .with_window_icon(Some(icon)) .with_maximized(maximized) - .with_transparent(true) - .with_decorations(!cmd_line_settings.frameless); + .with_transparent(true); + + let frame_decoration = cmd_line_settings.frame; + + // There is only two options for windows & linux, no need to match more options. + #[cfg(not(target_os = "macos"))] + let mut winit_window_builder = + winit_window_builder.with_decorations(frame_decoration == Frame::Full); + + #[cfg(target_os = "macos")] + let mut winit_window_builder = match frame_decoration { + Frame::Full => winit_window_builder, + Frame::None => winit_window_builder.with_decorations(false), + Frame::Buttonless => winit_window_builder + .with_transparent(true) + .with_title_hidden(true) + .with_titlebar_buttons_hidden(true) + .with_titlebar_transparent(true) + .with_fullsize_content_view(true), + Frame::Transparent => winit_window_builder + .with_title_hidden(true) + .with_titlebar_transparent(true) + .with_fullsize_content_view(true), + }; if let Some(previous_position) = previous_position { if !maximized {