mirror of
https://github.com/alacritty/alacritty.git
synced 2024-11-25 14:05:41 -05:00
Improve window.decorations options: (#1241)
The decorations config was changed from a bool to an enum. `full` has taken the place of `true`, and `none`, has replaced `false`. On macOS, there are now options for `transparent` and `buttonless`. These options are explained in both the CHANGELOG and in the configuration files.
This commit is contained in:
parent
641f3291eb
commit
3b46859ece
5 changed files with 243 additions and 57 deletions
|
@ -11,6 +11,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Implement the `hidden` escape sequence (`echo -e "\e[8mTEST"`)
|
||||
- Add support for macOS systemwide dark mode
|
||||
- Set the environment variable `COLORTERM="truecolor"` to advertise 24-bit color support
|
||||
- On macOS, there are two new values for the config option `window.decorations`:
|
||||
- `transparent` - This makes the title bar transparent and allows the
|
||||
viewport to extend to the top of the window.
|
||||
- `buttonless` - Similar to transparent but also removed the buttons.
|
||||
|
||||
### Changed
|
||||
|
||||
|
@ -23,6 +27,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
- Windows started as unfocused now show the hollow cursor if the setting is enabled
|
||||
- Bracketed paste mode now filters escape sequences beginning with \x1b
|
||||
|
||||
### Deprecated
|
||||
|
||||
- The config option `window.decorations` should now use `full` or `none` instead
|
||||
of `true` or `false`, respectively.
|
||||
|
||||
## Version 0.2.0
|
||||
|
||||
### Added
|
||||
|
|
|
@ -30,8 +30,10 @@ window:
|
|||
y: 2
|
||||
|
||||
# Window decorations
|
||||
# Setting this to false will result in window without borders and title bar.
|
||||
decorations: true
|
||||
# Available values:
|
||||
# - `full`: Window with borders and title bar.
|
||||
# - `none`: Window without borders or title bar.
|
||||
decorations: full
|
||||
|
||||
scrolling:
|
||||
# How many lines of scrollback to keep,
|
||||
|
|
|
@ -28,8 +28,14 @@ window:
|
|||
y: 2
|
||||
|
||||
# Window decorations
|
||||
# Setting this to false will result in window without borders and title bar.
|
||||
decorations: true
|
||||
# Available values:
|
||||
# - `full`: Window with title bar and title bar buttons
|
||||
# - `none`: Window without title bar, rounded corners, or drop shadow
|
||||
# - `transparent`: Window with title bar with transparent background and title
|
||||
# bar buttons
|
||||
# - `buttonless`: Window with title bar with transparent background and no
|
||||
# title bar buttons
|
||||
decorations: full
|
||||
|
||||
scrolling:
|
||||
# How many lines of scrollback to keep,
|
||||
|
|
|
@ -248,6 +248,89 @@ impl Default for Alpha {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum Decorations {
|
||||
Full,
|
||||
Transparent,
|
||||
Buttonless,
|
||||
None,
|
||||
}
|
||||
|
||||
impl Default for Decorations {
|
||||
fn default() -> Decorations {
|
||||
Decorations::Full
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for Decorations {
|
||||
fn deserialize<D>(deserializer: D) -> ::std::result::Result<Decorations, D::Error>
|
||||
where D: de::Deserializer<'de>
|
||||
{
|
||||
|
||||
struct DecorationsVisitor;
|
||||
|
||||
impl<'de> Visitor<'de> for DecorationsVisitor {
|
||||
type Value = Decorations;
|
||||
|
||||
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.write_str("Some subset of full|transparent|buttonless|none")
|
||||
}
|
||||
|
||||
fn visit_bool<E>(self, value: bool) -> ::std::result::Result<Decorations, E>
|
||||
where E: de::Error
|
||||
{
|
||||
if value {
|
||||
eprintln!("deprecated decorations boolean value, use one of default|transparent|buttonless|none instead; Falling back to \"full\"");
|
||||
Ok(Decorations::Full)
|
||||
} else {
|
||||
eprintln!("deprecated decorations boolean value, use one of default|transparent|buttonless|none instead; Falling back to \"none\"");
|
||||
Ok(Decorations::None)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
fn visit_str<E>(self, value: &str) -> ::std::result::Result<Decorations, E>
|
||||
where E: de::Error
|
||||
{
|
||||
match value {
|
||||
"transparent" => Ok(Decorations::Transparent),
|
||||
"buttonless" => Ok(Decorations::Buttonless),
|
||||
"none" => Ok(Decorations::None),
|
||||
"full" => Ok(Decorations::Full),
|
||||
_ => {
|
||||
eprintln!("invalid decorations value: {}; Using default value", value);
|
||||
Ok(Decorations::Full)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
fn visit_str<E>(self, value: &str) -> ::std::result::Result<Decorations, E>
|
||||
where E: de::Error
|
||||
{
|
||||
match value {
|
||||
"none" => Ok(Decorations::None),
|
||||
"full" => Ok(Decorations::Full),
|
||||
"transparent" => {
|
||||
eprintln!("macos-only decorations value: {}; Using default value", value);
|
||||
Ok(Decorations::Full)
|
||||
},
|
||||
"buttonless" => {
|
||||
eprintln!("macos-only decorations value: {}; Using default value", value);
|
||||
Ok(Decorations::Full)
|
||||
}
|
||||
_ => {
|
||||
eprintln!("invalid decorations value: {}; Using default value", value);
|
||||
Ok(Decorations::Full)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_str(DecorationsVisitor)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, Deserialize)]
|
||||
pub struct WindowConfig {
|
||||
/// Initial dimensions
|
||||
|
@ -259,8 +342,7 @@ pub struct WindowConfig {
|
|||
padding: Delta<u8>,
|
||||
|
||||
/// Draw the window with title bar / borders
|
||||
#[serde(default, deserialize_with = "failure_default")]
|
||||
decorations: bool,
|
||||
decorations: Decorations,
|
||||
}
|
||||
|
||||
fn default_padding() -> Delta<u8> {
|
||||
|
@ -280,7 +362,7 @@ fn deserialize_padding<'a, D>(deserializer: D) -> ::std::result::Result<Delta<u8
|
|||
}
|
||||
|
||||
impl WindowConfig {
|
||||
pub fn decorations(&self) -> bool {
|
||||
pub fn decorations(&self) -> Decorations {
|
||||
self.decorations
|
||||
}
|
||||
}
|
||||
|
@ -290,7 +372,7 @@ impl Default for WindowConfig {
|
|||
WindowConfig{
|
||||
dimensions: Default::default(),
|
||||
padding: default_padding(),
|
||||
decorations: true,
|
||||
decorations: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
185
src/window.rs
185
src/window.rs
|
@ -16,14 +16,16 @@ use std::fmt::{self, Display};
|
|||
use std::ops::Deref;
|
||||
|
||||
use gl;
|
||||
use glutin::{self, ContextBuilder, ControlFlow, CursorState, Event, EventsLoop,
|
||||
MouseCursor as GlutinMouseCursor, WindowBuilder};
|
||||
use glutin::GlContext;
|
||||
use glutin::{
|
||||
self, ContextBuilder, ControlFlow, CursorState, Event, EventsLoop,
|
||||
MouseCursor as GlutinMouseCursor, WindowBuilder,
|
||||
};
|
||||
|
||||
use MouseCursor;
|
||||
|
||||
use cli::Options;
|
||||
use config::WindowConfig;
|
||||
use config::{Decorations, WindowConfig};
|
||||
|
||||
/// Default text for the window's title bar, if not overriden.
|
||||
///
|
||||
|
@ -119,7 +121,7 @@ impl ToPoints for Size<Pixels<u32>> {
|
|||
|
||||
Size {
|
||||
width: Points(width_pts),
|
||||
height: Points(height_pts)
|
||||
height: Points(height_pts),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -147,7 +149,6 @@ macro_rules! deref_newtype {
|
|||
|
||||
deref_newtype! { Points<T>, Pixels<T> }
|
||||
|
||||
|
||||
impl<T: Display> Display for Pixels<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}px", self.0)
|
||||
|
@ -179,12 +180,8 @@ impl ::std::error::Error for Error {
|
|||
impl Display for Error {
|
||||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
|
||||
match *self {
|
||||
Error::ContextCreation(ref err) => {
|
||||
write!(f, "Error creating GL context; {}", err)
|
||||
},
|
||||
Error::Context(ref err) => {
|
||||
write!(f, "Error operating on render context; {}", err)
|
||||
},
|
||||
Error::ContextCreation(ref err) => write!(f, "Error creating GL context; {}", err),
|
||||
Error::Context(ref err) => write!(f, "Error operating on render context; {}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -206,9 +203,7 @@ fn create_gl_window(
|
|||
event_loop: &EventsLoop,
|
||||
srgb: bool,
|
||||
) -> ::std::result::Result<glutin::GlWindow, glutin::CreationError> {
|
||||
let context = ContextBuilder::new()
|
||||
.with_srgb(srgb)
|
||||
.with_vsync(true);
|
||||
let context = ContextBuilder::new().with_srgb(srgb).with_vsync(true);
|
||||
::glutin::GlWindow::new(window, context, event_loop)
|
||||
}
|
||||
|
||||
|
@ -216,19 +211,12 @@ impl Window {
|
|||
/// Create a new window
|
||||
///
|
||||
/// This creates a window and fully initializes a window.
|
||||
pub fn new(
|
||||
options: &Options,
|
||||
window_config: &WindowConfig,
|
||||
) -> Result<Window> {
|
||||
pub fn new(options: &Options, window_config: &WindowConfig) -> Result<Window> {
|
||||
let event_loop = EventsLoop::new();
|
||||
|
||||
let title = options.title.as_ref().map_or(DEFAULT_TITLE, |t| t);
|
||||
let class = options.class.as_ref().map_or(DEFAULT_CLASS, |c| c);
|
||||
let window_builder = WindowBuilder::new()
|
||||
.with_title(title)
|
||||
.with_visibility(false)
|
||||
.with_transparency(true)
|
||||
.with_decorations(window_config.decorations());
|
||||
let window_builder = Window::get_platform_window(title, window_config);
|
||||
let window_builder = Window::platform_builder_ext(window_builder, &class);
|
||||
let window = create_gl_window(window_builder.clone(), &event_loop, false)
|
||||
.or_else(|_| create_gl_window(window_builder, &event_loop, true))?;
|
||||
|
@ -268,9 +256,10 @@ impl Window {
|
|||
}
|
||||
|
||||
pub fn inner_size_pixels(&self) -> Option<Size<Pixels<u32>>> {
|
||||
self.window
|
||||
.get_inner_size()
|
||||
.map(|(w, h)| Size { width: Pixels(w), height: Pixels(h) })
|
||||
self.window.get_inner_size().map(|(w, h)| Size {
|
||||
width: Pixels(w),
|
||||
height: Pixels(h),
|
||||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -287,15 +276,14 @@ impl Window {
|
|||
|
||||
#[inline]
|
||||
pub fn swap_buffers(&self) -> Result<()> {
|
||||
self.window
|
||||
.swap_buffers()
|
||||
.map_err(From::from)
|
||||
self.window.swap_buffers().map_err(From::from)
|
||||
}
|
||||
|
||||
/// Poll for any available events
|
||||
#[inline]
|
||||
pub fn poll_events<F>(&mut self, func: F)
|
||||
where F: FnMut(Event)
|
||||
where
|
||||
F: FnMut(Event),
|
||||
{
|
||||
self.event_loop.poll_events(func);
|
||||
}
|
||||
|
@ -308,7 +296,8 @@ impl Window {
|
|||
/// Block waiting for events
|
||||
#[inline]
|
||||
pub fn wait_events<F>(&mut self, func: F)
|
||||
where F: FnMut(Event) -> ControlFlow
|
||||
where
|
||||
F: FnMut(Event) -> ControlFlow,
|
||||
{
|
||||
self.event_loop.run_forever(func);
|
||||
}
|
||||
|
@ -341,24 +330,95 @@ impl Window {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))]
|
||||
#[cfg(
|
||||
any(
|
||||
target_os = "linux",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd"
|
||||
)
|
||||
)]
|
||||
fn platform_builder_ext(window_builder: WindowBuilder, wm_class: &str) -> WindowBuilder {
|
||||
use glutin::os::unix::WindowBuilderExt;
|
||||
window_builder.with_class(wm_class.to_owned(), "Alacritty".to_owned())
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd")))]
|
||||
#[cfg(
|
||||
not(
|
||||
any(
|
||||
target_os = "linux",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd"
|
||||
)
|
||||
)
|
||||
)]
|
||||
fn platform_builder_ext(window_builder: WindowBuilder, _: &str) -> WindowBuilder {
|
||||
window_builder
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd"))]
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
pub fn get_platform_window(title: &str, window_config: &WindowConfig) -> WindowBuilder {
|
||||
let decorations = match window_config.decorations() {
|
||||
Decorations::None => false,
|
||||
_ => true,
|
||||
};
|
||||
|
||||
WindowBuilder::new()
|
||||
.with_title(title)
|
||||
.with_visibility(false)
|
||||
.with_transparency(true)
|
||||
.with_decorations(decorations)
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
pub fn get_platform_window(title: &str, window_config: &WindowConfig) -> WindowBuilder {
|
||||
use glutin::os::macos::WindowBuilderExt;
|
||||
|
||||
let window = WindowBuilder::new()
|
||||
.with_title(title)
|
||||
.with_visibility(false)
|
||||
.with_transparency(true);
|
||||
|
||||
match window_config.decorations() {
|
||||
Decorations::Full => window,
|
||||
Decorations::Transparent => window
|
||||
.with_title_hidden(true)
|
||||
.with_titlebar_transparent(true)
|
||||
.with_fullsize_content_view(true),
|
||||
Decorations::Buttonless => window
|
||||
.with_title_hidden(true)
|
||||
.with_titlebar_buttons_hidden(true)
|
||||
.with_titlebar_transparent(true)
|
||||
.with_fullsize_content_view(true),
|
||||
Decorations::None => window
|
||||
.with_titlebar_hidden(true),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(
|
||||
any(
|
||||
target_os = "linux",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd"
|
||||
)
|
||||
)]
|
||||
pub fn set_urgent(&self, is_urgent: bool) {
|
||||
use glutin::os::unix::WindowExt;
|
||||
self.window.set_urgent(is_urgent);
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd")))]
|
||||
#[cfg(
|
||||
not(
|
||||
any(
|
||||
target_os = "linux",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd"
|
||||
)
|
||||
)
|
||||
)]
|
||||
pub fn set_urgent(&self, _is_urgent: bool) {}
|
||||
|
||||
pub fn set_ime_spot(&self, x: i32, y: i32) {
|
||||
|
@ -371,7 +431,7 @@ impl Window {
|
|||
|
||||
match self.window.get_xlib_window() {
|
||||
Some(xlib_window) => Some(xlib_window as usize),
|
||||
None => None
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -390,17 +450,28 @@ pub trait OsExtensions {
|
|||
fn run_os_extensions(&self) {}
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_os = "linux", target_os = "freebsd", target_os="dragonfly", target_os="openbsd")))]
|
||||
impl OsExtensions for Window { }
|
||||
#[cfg(
|
||||
not(
|
||||
any(
|
||||
target_os = "linux",
|
||||
target_os = "freebsd",
|
||||
target_os = "dragonfly",
|
||||
target_os = "openbsd"
|
||||
)
|
||||
)
|
||||
)]
|
||||
impl OsExtensions for Window {}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os="dragonfly", target_os="openbsd"))]
|
||||
#[cfg(
|
||||
any(target_os = "linux", target_os = "freebsd", target_os = "dragonfly", target_os = "openbsd")
|
||||
)]
|
||||
impl OsExtensions for Window {
|
||||
fn run_os_extensions(&self) {
|
||||
use glutin::os::unix::WindowExt;
|
||||
use x11_dl::xlib::{self, XA_CARDINAL, PropModeReplace};
|
||||
use std::ffi::{CStr};
|
||||
use std::ptr;
|
||||
use libc::getpid;
|
||||
use std::ffi::CStr;
|
||||
use std::ptr;
|
||||
use x11_dl::xlib::{self, PropModeReplace, XA_CARDINAL};
|
||||
|
||||
let xlib_display = self.window.get_xlib_display();
|
||||
let xlib_window = self.window.get_xlib_window();
|
||||
|
@ -414,17 +485,32 @@ impl OsExtensions for Window {
|
|||
let atom = (xlib.XInternAtom)(xlib_display as *mut _, _net_wm_pid.as_ptr(), 0);
|
||||
let pid = getpid();
|
||||
|
||||
(xlib.XChangeProperty)(xlib_display as _, xlib_window as _, atom,
|
||||
XA_CARDINAL, 32, PropModeReplace, &pid as *const i32 as *const u8, 1);
|
||||
|
||||
(xlib.XChangeProperty)(
|
||||
xlib_display as _,
|
||||
xlib_window as _,
|
||||
atom,
|
||||
XA_CARDINAL,
|
||||
32,
|
||||
PropModeReplace,
|
||||
&pid as *const i32 as *const u8,
|
||||
1,
|
||||
);
|
||||
}
|
||||
// Although this call doesn't actually pass any data, it does cause
|
||||
// WM_CLIENT_MACHINE to be set. WM_CLIENT_MACHINE MUST be set if _NET_WM_PID is set
|
||||
// (which we do above).
|
||||
unsafe {
|
||||
(xlib.XSetWMProperties)(xlib_display as _, xlib_window as _, ptr::null_mut(),
|
||||
ptr::null_mut(), ptr::null_mut(), 0, ptr::null_mut(), ptr::null_mut(),
|
||||
ptr::null_mut());
|
||||
(xlib.XSetWMProperties)(
|
||||
xlib_display as _,
|
||||
xlib_window as _,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
0,
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
ptr::null_mut(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -447,6 +533,7 @@ pub trait SetInnerSize<T> {
|
|||
impl SetInnerSize<Pixels<u32>> for Window {
|
||||
fn set_inner_size<T: ToPoints>(&mut self, size: &T) {
|
||||
let size = size.to_points(self.hidpi_factor());
|
||||
self.window.set_inner_size(*size.width as _, *size.height as _);
|
||||
self.window
|
||||
.set_inner_size(*size.width as _, *size.height as _);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue