1
1
mirror of https://github.com/wez/wezterm.git synced 2024-11-22 22:42:48 +03:00

integrated-title-bar: Update config options

and rename the "FANCY" option to "INTEGRATED_BUTTONS"
This commit is contained in:
YuraIz 2022-11-17 21:02:42 +03:00 committed by Wez Furlong
parent c553646ea4
commit 01aeb506c0
No known key found for this signature in database
GPG Key ID: 7A7F66A31EC9B387
8 changed files with 136 additions and 202 deletions

View File

@ -42,7 +42,8 @@ use wezterm_bidi::ParagraphDirectionHint;
use wezterm_config_derive::ConfigMeta;
use wezterm_dynamic::{FromDynamic, ToDynamic};
use wezterm_input_types::{
FancyWindowDecorations, Modifiers, UIKeyCapRendering, WindowDecorations,
IntegratedTitleButton, IntegratedTitleButtonAlignment, IntegratedTitleButtonStyle, Modifiers,
UIKeyCapRendering, WindowDecorations,
};
use wezterm_term::TerminalSize;
@ -79,14 +80,17 @@ pub struct Config {
#[dynamic(default)]
pub window_decorations: WindowDecorations,
/// Controls window buttons position and style
/// for fancy window decorations.
/// Has no effect on macOS or Windows.
#[dynamic(default = "default_integrated_title_buttons")]
pub integrated_title_buttons: Vec<IntegratedTitleButton>,
#[dynamic(default)]
pub log_unknown_escape_sequences: bool,
#[dynamic(default)]
pub fancy_window_decorations: FancyWindowDecorations,
pub integrated_title_button_alignment: IntegratedTitleButtonAlignment,
#[dynamic(default)]
pub integrated_title_button_style: IntegratedTitleButtonStyle,
/// When using FontKitXXX font systems, a set of directories to
/// search ahead of the standard font locations for fonts.
@ -1467,6 +1471,11 @@ fn default_pane_select_font_size() -> f64 {
36.0
}
fn default_integrated_title_buttons() -> Vec<IntegratedTitleButton> {
use IntegratedTitleButton::*;
vec![Hide, Maximize, Close]
}
fn default_char_select_font_size() -> f64 {
18.0
}

View File

@ -10,6 +10,9 @@ use termwiz::escape::{Action, ControlCode, CSI};
use termwiz::surface::SEQ_ZERO;
use termwiz_funcs::{format_as_escapes, FormatItem};
use wezterm_term::Line;
use window::IntegratedTitleButton;
#[cfg(not(target_os = "macos"))]
use window::IntegratedTitleButtonAlignment;
#[derive(Clone, Debug, PartialEq)]
pub struct TabBarState {
@ -24,9 +27,7 @@ pub enum TabBarItem {
RightStatus,
Tab { tab_idx: usize, active: bool },
NewTabButton,
WindowHideButton,
WindowMaximizeButton,
WindowCloseButton,
WindowButton(IntegratedTitleButton),
}
#[derive(Clone, Debug, PartialEq)]
@ -184,7 +185,7 @@ impl TabBarState {
// MacOS uses native buttons.
#[cfg(not(target_os = "macos"))]
fn fancy_window_decorations(
fn integrated_title_buttons(
mouse_x: Option<usize>,
x: &mut usize,
config: &ConfigHandle,
@ -243,71 +244,43 @@ impl TabBarState {
},
);
let window::FancyWindowDecorations {
is_left,
remove_hide_button,
remove_maximize_button,
..
} = if cfg!(any(windows, target_os = "macos")) {
// Ignore changes to config on windows and macos
window::FancyWindowDecorations::default()
} else {
config.fancy_window_decorations.clone()
};
let button_order = if is_left {
['X', '.', '-']
} else {
['.', '-', 'X']
};
for button in button_order {
let (title, item) = match button {
// Window hide button
'.' if !remove_hide_button => {
for button in &config.integrated_title_buttons {
use IntegratedTitleButton as Button;
let title = match button {
Button::Hide => {
let hover = is_tab_hover(mouse_x, *x, window_hide_hover.len());
let window_hide_button = if hover {
if hover {
&window_hide_hover
} else {
&window_hide
};
(window_hide_button, TabBarItem::WindowHideButton)
}
}
'-' if !remove_maximize_button => {
// Window maximize button
Button::Maximize => {
let hover = is_tab_hover(mouse_x, *x, window_maximize_hover.len());
let window_maximize_button = if hover {
if hover {
&window_maximize_hover
} else {
&window_maximize
};
(window_maximize_button, TabBarItem::WindowMaximizeButton)
}
}
'X' => {
// Window close button
Button::Close => {
let hover = is_tab_hover(mouse_x, *x, window_close_hover.len());
let window_close_button = if hover {
if hover {
&window_close_hover
} else {
&window_close
};
(window_close_button, TabBarItem::WindowCloseButton)
}
}
_ => continue,
};
let width = title.len();
line.append_line(title.to_owned(), SEQ_ZERO);
let width = title.len();
items.push(TabEntry {
item,
item: TabBarItem::WindowButton(*button),
title: title.to_owned(),
x: *x,
width,
@ -356,9 +329,9 @@ impl TabBarState {
},
);
let fancy_window_decorations = config
let use_integrated_title_buttons = config
.window_decorations
.contains(window::WindowDecorations::FANCY);
.contains(window::WindowDecorations::INTEGRATED_BUTTONS);
// We ultimately want to produce a line looking like this:
// ` | tab1-title x | tab2-title x | + . - X `
@ -408,8 +381,11 @@ impl TabBarState {
let mut items = vec![];
#[cfg(not(target_os = "macos"))]
if fancy_window_decorations && config.fancy_window_decorations.is_left && !cfg!(widnows) {
Self::fancy_window_decorations(mouse_x, &mut x, config, &mut items, &mut line, &colors);
if use_integrated_title_buttons
&& config.integrated_title_button_alignment == IntegratedTitleButtonAlignment::Left
&& !cfg!(widnows)
{
Self::integrated_title_buttons(mouse_x, &mut x, config, &mut items, &mut line, &colors);
}
let black_cell = Cell::blank_with_attrs(
@ -419,7 +395,7 @@ impl TabBarState {
);
#[cfg(target_os = "macos")]
if fancy_window_decorations && config.use_fancy_tab_bar == false {
if use_integrated_title_buttons && config.use_fancy_tab_bar == false {
for _ in 0..10 as usize {
line.insert_cell(x, black_cell.clone(), title_width, SEQ_ZERO);
x += 1;
@ -513,10 +489,10 @@ impl TabBarState {
x += width;
}
// Reserve place for buttons
// Reserve place for integrated title buttons
#[cfg(not(target_os = "macos"))]
let title_width = if fancy_window_decorations
&& !config.fancy_window_decorations.is_left
let title_width = if use_integrated_title_buttons
&& config.integrated_title_button_alignment == IntegratedTitleButtonAlignment::Right
&& !cfg!(target_os = "macos")
{
let window_hide =
@ -547,7 +523,18 @@ impl TabBarState {
let maximize_len = window_maximize.len().max(window_maximize_hover.len());
let close_len = window_close.len().max(window_close_hover.len());
title_width.saturating_sub(hide_len + maximize_len + close_len)
let mut width_to_reserve = 0;
for button in &config.integrated_title_buttons {
use IntegratedTitleButton as Button;
let button_len = match button {
Button::Hide => hide_len,
Button::Maximize => maximize_len,
Button::Close => close_len,
};
width_to_reserve += button_len;
}
title_width.saturating_sub(width_to_reserve)
} else {
title_width
};
@ -572,9 +559,11 @@ impl TabBarState {
}
#[cfg(not(target_os = "macos"))]
if fancy_window_decorations && !config.fancy_window_decorations.is_left {
if use_integrated_title_buttons
&& config.integrated_title_button_alignment == IntegratedTitleButtonAlignment::Right
{
x = title_width;
Self::fancy_window_decorations(mouse_x, &mut x, config, &mut items, &mut line, &colors);
Self::integrated_title_buttons(mouse_x, &mut x, config, &mut items, &mut line, &colors);
}
Self { line, items }

View File

@ -478,28 +478,25 @@ impl super::TermWindow {
}
context.request_drag_move();
}
TabBarItem::WindowHideButton => {
TabBarItem::WindowButton(button) => {
use window::IntegratedTitleButton as Button;
if let Some(ref window) = self.window {
window.hide();
}
}
TabBarItem::WindowMaximizeButton => {
if let Some(ref window) = self.window {
let maximized = self
.window_state
.intersects(WindowState::MAXIMIZED | WindowState::FULL_SCREEN);
if maximized {
window.restore();
} else {
window.maximize();
match button {
Button::Hide => window.hide(),
Button::Maximize => {
let maximized = self
.window_state
.intersects(WindowState::MAXIMIZED | WindowState::FULL_SCREEN);
if maximized {
window.restore();
} else {
window.maximize();
}
}
Button::Close => self.close_requested(&window.clone()),
}
}
}
TabBarItem::WindowCloseButton => {
if let Some(ref window) = self.window {
self.close_requested(&window.clone());
}
}
},
WMEK::Press(MousePress::Middle) => match item {
TabBarItem::Tab { tab_idx, .. } => {
@ -511,9 +508,7 @@ impl super::TermWindow {
TabBarItem::None
| TabBarItem::LeftStatus
| TabBarItem::RightStatus
| TabBarItem::WindowHideButton
| TabBarItem::WindowMaximizeButton
| TabBarItem::WindowCloseButton => {}
| TabBarItem::WindowButton(_) => {}
},
WMEK::Press(MousePress::Right) => match item {
TabBarItem::Tab { .. } => {
@ -525,17 +520,13 @@ impl super::TermWindow {
TabBarItem::None
| TabBarItem::LeftStatus
| TabBarItem::RightStatus
| TabBarItem::WindowHideButton
| TabBarItem::WindowMaximizeButton
| TabBarItem::WindowCloseButton => {}
| TabBarItem::WindowButton(_) => {}
},
WMEK::Move => match item {
TabBarItem::None | TabBarItem::LeftStatus | TabBarItem::RightStatus => {
context.set_window_drag_position(event.screen_coords);
}
TabBarItem::WindowHideButton
| TabBarItem::WindowMaximizeButton
| TabBarItem::WindowCloseButton
TabBarItem::WindowButton(_)
| TabBarItem::Tab { .. }
| TabBarItem::NewTabButton { .. } => {}
},

View File

@ -50,6 +50,7 @@ use wezterm_font::{ClearShapeCache, GlyphInfo, LoadedFont};
use wezterm_term::color::{ColorAttribute, ColorPalette, RgbColor};
use wezterm_term::{CellAttributes, Line, StableRowIndex};
use window::color::LinearRgba;
use window::{IntegratedTitleButton, IntegratedTitleButtonAlignment};
pub const TOP_LEFT_ROUNDED_CORNER: &[Poly] = &[Poly {
path: &[
@ -279,14 +280,15 @@ mod window_buttons {
}
fn window_button_element(
window_button: TabBarItem,
window_button: IntegratedTitleButton,
is_maximized: bool,
font: &Rc<LoadedFont>,
metrics: &RenderMetrics,
colors: &TabBarColors,
style: window::FancyWindowDecorationsStyle,
style: window::IntegratedTitleButtonStyle,
) -> Element {
use window::FancyWindowDecorationsStyle as Style;
use window::IntegratedTitleButtonStyle as Style;
use IntegratedTitleButton as Button;
#[cfg(windows)]
let style = Style::Windows;
@ -295,31 +297,30 @@ fn window_button_element(
Style::Windows => {
use window_buttons::windows::{CLOSE, HIDE, MAXIMIZE, RESTORE};
match window_button {
TabBarItem::WindowHideButton => HIDE,
TabBarItem::WindowMaximizeButton => {
Button::Hide => HIDE,
Button::Maximize => {
if is_maximized {
RESTORE
} else {
MAXIMIZE
}
}
TabBarItem::WindowCloseButton => CLOSE,
_ => unreachable!(),
Button::Close => CLOSE,
}
}
Style::Gnome => {
use window_buttons::gnome::{CLOSE, HIDE, MAXIMIZE, RESTORE};
match window_button {
TabBarItem::WindowHideButton => HIDE,
TabBarItem::WindowMaximizeButton => {
Button::Hide => HIDE,
Button::Maximize => {
if is_maximized {
RESTORE
} else {
MAXIMIZE
}
}
TabBarItem::WindowCloseButton => CLOSE,
_ => unreachable!(),
Button::Close => CLOSE,
}
}
};
@ -340,7 +341,7 @@ fn window_button_element(
let element = match style {
Style::Windows => {
let left_padding = match window_button {
TabBarItem::WindowHideButton => 17.0,
Button::Hide => 17.0,
_ => 18.0,
};
let scale = 72.0 / 96.0;
@ -396,16 +397,13 @@ fn window_button_element(
};
let (color, hover_colors) = match window_button {
TabBarItem::WindowHideButton => (colors.window_hide(), colors.window_hide_hover()),
TabBarItem::WindowMaximizeButton => {
(colors.window_maximize(), colors.window_maximize_hover())
}
TabBarItem::WindowCloseButton => (colors.window_close(), colors.window_close_hover()),
_ => unreachable!(),
Button::Hide => (colors.window_hide(), colors.window_hide_hover()),
Button::Maximize => (colors.window_maximize(), colors.window_maximize_hover()),
Button::Close => (colors.window_close(), colors.window_close_hover()),
};
let element = element
.item_type(UIItemType::TabBar(window_button))
.item_type(UIItemType::TabBar(TabBarItem::WindowButton(window_button)))
.colors(ElementColors {
border: BorderColor::new(color.bg_color.to_linear()),
bg: color.bg_color.to_linear().into(),
@ -1082,15 +1080,13 @@ impl super::TermWindow {
.into(),
})
}),
TabBarItem::WindowHideButton
| TabBarItem::WindowMaximizeButton
| TabBarItem::WindowCloseButton => window_button_element(
item.item.clone(),
TabBarItem::WindowButton(button) => window_button_element(
button,
self.window_state.contains(window::WindowState::MAXIMIZED),
&font,
&metrics,
&colors,
self.config.fancy_window_decorations.style,
self.config.integrated_title_button_style,
),
}
};
@ -1110,10 +1106,11 @@ impl super::TermWindow {
match item.item {
TabBarItem::LeftStatus => left_status.push(item_to_elem(item)),
TabBarItem::None | TabBarItem::RightStatus => right_eles.push(item_to_elem(item)),
TabBarItem::WindowHideButton
| TabBarItem::WindowMaximizeButton
| TabBarItem::WindowCloseButton => {
if self.config.fancy_window_decorations.is_left && cfg!(not(windows)) {
TabBarItem::WindowButton(_) => {
if self.config.integrated_title_button_alignment
== IntegratedTitleButtonAlignment::Left
&& cfg!(not(windows))
{
left_eles.push(item_to_elem(item))
} else {
right_eles.push(item_to_elem(item))
@ -1202,8 +1199,9 @@ impl super::TermWindow {
}
let window_buttons_at_left = self.config.window_decorations
== window::WindowDecorations::FANCY
&& (self.config.fancy_window_decorations.is_left
== window::WindowDecorations::INTEGRATED_BUTTONS
&& (self.config.integrated_title_button_alignment
== IntegratedTitleButtonAlignment::Left
|| (cfg!(target_os = "macos")) && cfg!(not(windows)));
let left_padding = if window_buttons_at_left {

View File

@ -1390,7 +1390,7 @@ bitflags! {
// so that we effective have Option<bool>
const MACOS_FORCE_DISABLE_SHADOW = 4;
const MACOS_FORCE_ENABLE_SHADOW = 4|8;
const FANCY = 16;
const INTEGRATED_BUTTONS = 16;
}
}
@ -1403,8 +1403,8 @@ impl Into<String> for &WindowDecorations {
if self.contains(WindowDecorations::RESIZE) {
s.push("RESIZE");
}
if self.contains(WindowDecorations::FANCY) {
s.push("FANCY");
if self.contains(WindowDecorations::INTEGRATED_BUTTONS) {
s.push("INTEGRATED_BUTTONS");
}
if self.contains(WindowDecorations::MACOS_FORCE_ENABLE_SHADOW) {
s.push("MACOS_FORCE_ENABLE_SHADOW");
@ -1435,8 +1435,8 @@ impl TryFrom<String> for WindowDecorations {
flags |= Self::MACOS_FORCE_DISABLE_SHADOW;
} else if ele == "MACOS_FORCE_ENABLE_SHADOW" {
flags |= Self::MACOS_FORCE_ENABLE_SHADOW;
} else if ele == "FANCY" {
flags |= Self::FANCY;
} else if ele == "INTEGRATED_BUTTONS" {
flags |= Self::INTEGRATED_BUTTONS;
} else {
return Err(format!("invalid WindowDecoration name {} in {}", ele, s));
}
@ -1451,84 +1451,27 @@ impl Default for WindowDecorations {
}
}
#[derive(Debug, FromDynamic, ToDynamic, Clone)]
pub struct FancyWindowDecorations {
#[dynamic(default)]
pub is_left: bool,
#[dynamic(default)]
pub remove_hide_button: bool,
#[dynamic(default)]
pub remove_maximize_button: bool,
#[dynamic(default)]
pub style: FancyWindowDecorationsStyle,
#[derive(Debug, FromDynamic, ToDynamic, PartialEq, Eq, Clone, Copy)]
pub enum IntegratedTitleButton {
Hide,
Maximize,
Close,
}
#[cfg(not(target_os = "macos"))]
impl Default for FancyWindowDecorations {
fn default() -> Self {
FancyWindowDecorations {
is_left: false,
remove_hide_button: false,
remove_maximize_button: false,
style: Default::default(),
}
}
#[derive(Debug, Default, FromDynamic, ToDynamic, PartialEq, Eq, Clone, Copy)]
pub enum IntegratedTitleButtonAlignment {
#[default]
Right,
Left,
}
#[cfg(target_os = "macos")]
impl Default for FancyWindowDecorations {
fn default() -> Self {
FancyWindowDecorations {
is_left: true,
remove_hide_button: false,
remove_maximize_button: false,
style: Default::default(),
}
}
}
#[derive(Debug, Deserialize, Serialize, FromDynamic, ToDynamic, Clone, Copy)]
#[dynamic(try_from = "String")]
pub enum FancyWindowDecorationsStyle {
#[derive(Debug, Default, FromDynamic, ToDynamic, Clone, Copy)]
pub enum IntegratedTitleButtonStyle {
#[default]
Windows,
Gnome,
}
#[cfg(not(target_os = "linux"))]
impl Default for FancyWindowDecorationsStyle {
fn default() -> Self {
Self::Windows
}
}
#[cfg(target_os = "linux")]
impl Default for FancyWindowDecorationsStyle {
fn default() -> Self {
Self::Gnome
}
}
impl Into<String> for FancyWindowDecorationsStyle {
fn into(self) -> String {
match self {
Self::Windows => "windows",
Self::Gnome => "gnome",
}
.to_string()
}
}
impl TryFrom<String> for FancyWindowDecorationsStyle {
type Error = String;
fn try_from(value: String) -> Result<Self, Self::Error> {
match value.to_lowercase().as_str() {
"windows" => Ok(Self::Windows),
"gnome" => Ok(Self::Gnome),
_ => Err(format!("invalid fancy_window_decoratins.style {}", value)),
}
}
}
/// Map c to its Ctrl equivalent.
/// In theory, this mapping is simply translating alpha characters
/// to upper case and then masking them by 0x1f, but xterm inherits

View File

@ -1230,7 +1230,7 @@ fn apply_decorations_to_window(window: &StrongPtr, decorations: WindowDecoration
window.setStyleMask_(mask);
let hidden = if decorations.contains(WindowDecorations::TITLE)
|| decorations.contains(WindowDecorations::FANCY)
|| decorations.contains(WindowDecorations::INTEGRATED_BUTTONS)
{
NO
} else {
@ -1252,7 +1252,7 @@ fn apply_decorations_to_window(window: &StrongPtr, decorations: WindowDecoration
} else {
appkit::NSWindowTitleVisibility::NSWindowTitleHidden
});
if decorations == WindowDecorations::FANCY {
if decorations == WindowDecorations::INTEGRATED_BUTTONS {
window.setTitlebarAppearsTransparent_(YES);
} else {
window.setTitlebarAppearsTransparent_(hidden);
@ -1270,7 +1270,9 @@ fn decoration_to_mask(decorations: WindowDecorations) -> NSWindowStyleMask {
| NSWindowStyleMask::NSClosableWindowMask
| NSWindowStyleMask::NSMiniaturizableWindowMask
| NSWindowStyleMask::NSResizableWindowMask
} else if decorations == WindowDecorations::RESIZE || decorations == WindowDecorations::FANCY {
} else if decorations == WindowDecorations::RESIZE
|| decorations == WindowDecorations::INTEGRATED_BUTTONS
{
NSWindowStyleMask::NSTitledWindowMask
| NSWindowStyleMask::NSClosableWindowMask
| NSWindowStyleMask::NSMiniaturizableWindowMask

View File

@ -1038,7 +1038,7 @@ unsafe fn wm_nccalcsize(hwnd: HWND, _msg: UINT, wparam: WPARAM, lparam: LPARAM)
let inner = inner.borrow_mut();
if !(wparam == 1 && (inner.config.window_decorations == WindowDecorations::RESIZE)
|| (inner.config.window_decorations == WindowDecorations::FANCY))
|| (inner.config.window_decorations == WindowDecorations::INTEGRATED_BUTTONS))
{
return None;
}
@ -1100,7 +1100,7 @@ unsafe fn wm_nchittest(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM) ->
let inner = inner.borrow_mut();
match inner.config.window_decorations {
WindowDecorations::FANCY | WindowDecorations::RESIZE => {}
WindowDecorations::INTEGRATED_BUTTONS | WindowDecorations::RESIZE => {}
_ => return None,
}
@ -1172,7 +1172,8 @@ unsafe fn wm_nchittest(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM) ->
}
}
if inner.config.window_decorations == WindowDecorations::FANCY && inner.config.use_fancy_tab_bar
if inner.config.window_decorations == WindowDecorations::INTEGRATED_BUTTONS
&& inner.config.use_fancy_tab_bar
{
let scale = GetDpiForWindow(inner.hwnd.0) as f64 / 96.0;
let button_height = (30.0 * scale) as isize;
@ -2700,7 +2701,8 @@ unsafe fn do_wnd_proc(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM) ->
) {
let inner = rc_from_hwnd(hwnd)?;
let inner = inner.borrow();
let use_shap_layouts = inner.config.window_decorations == WindowDecorations::FANCY
let use_shap_layouts = inner.config.window_decorations
== WindowDecorations::INTEGRATED_BUTTONS
&& inner.config.use_fancy_tab_bar;
std::mem::drop(inner);
if use_shap_layouts {

View File

@ -952,7 +952,7 @@ impl XWindowInner {
let decorations = if decorations == WindowDecorations::TITLE | WindowDecorations::RESIZE {
FUNC_ALL
} else if decorations == WindowDecorations::RESIZE
|| decorations == WindowDecorations::FANCY
|| decorations == WindowDecorations::INTEGRATED_BUTTONS
{
FUNC_RESIZE
} else if decorations == WindowDecorations::TITLE {