From 209d039c5dc671c72366f4ce64482b9b888723d3 Mon Sep 17 00:00:00 2001 From: rawnly Date: Fri, 1 Dec 2023 21:06:21 +0100 Subject: [PATCH] fix: refactor window level + Toggle options --- config/src/keyassignment.rs | 12 ++---- config/src/lib.rs | 1 + config/src/window.rs | 9 +++++ wezterm-gui/src/commands.rs | 38 +++++++++++++----- wezterm-gui/src/termwindow/mod.rs | 67 +++++++++++++++++++++++++------ window/src/lib.rs | 18 +++++---- window/src/os/macos/window.rs | 4 +- 7 files changed, 111 insertions(+), 38 deletions(-) create mode 100644 config/src/window.rs diff --git a/config/src/keyassignment.rs b/config/src/keyassignment.rs index ae1cc84fa..ffe10db05 100644 --- a/config/src/keyassignment.rs +++ b/config/src/keyassignment.rs @@ -1,5 +1,6 @@ use crate::default_true; use crate::keys::KeyNoAction; +use crate::window::WindowLevel; use luahelper::impl_lua_conversion_dynamic; use ordered_float::NotNan; use portable_pty::CommandBuilder; @@ -501,20 +502,15 @@ fn default_fuzzy_description() -> String { "Fuzzy matching: ".to_string() } -// FIXME: this is so ugly we should use `window::WindowLevel` instead -#[derive(Debug, Clone, PartialEq, FromDynamic, ToDynamic)] -pub enum SetWindowLevelLevel { - Normal, - AlwaysOnTop, - AlwaysOnBottom, -} #[derive(Debug, Clone, PartialEq, FromDynamic, ToDynamic)] pub enum KeyAssignment { SpawnTab(SpawnTabDomain), SpawnWindow, ToggleFullScreen, - SetWindowLevel(SetWindowLevelLevel), + ToggleAlwaysOnTop, + ToggleAlwaysOnBottom, + SetWindowLevel(WindowLevel), CopyTo(ClipboardCopyDestination), CopyTextTo { text: String, diff --git a/config/src/lib.rs b/config/src/lib.rs index 9b1e5f071..5315cf921 100644 --- a/config/src/lib.rs +++ b/config/src/lib.rs @@ -19,6 +19,7 @@ use std::sync::{Arc, Mutex}; use std::time::Duration; use wezterm_dynamic::{FromDynamic, FromDynamicOptions, ToDynamic, UnknownFieldAction, Value}; +pub mod window; mod background; mod bell; mod color; diff --git a/config/src/window.rs b/config/src/window.rs new file mode 100644 index 000000000..121b76d0c --- /dev/null +++ b/config/src/window.rs @@ -0,0 +1,9 @@ +use wezterm_dynamic::{ToDynamic, FromDynamic}; + + +#[derive(Debug, Clone, ToDynamic, PartialEq, Eq, FromDynamic)] +pub enum WindowLevel { + AlwaysOnBottom = -1, + Normal = 0, + AlwaysOnTop = 3, +} diff --git a/wezterm-gui/src/commands.rs b/wezterm-gui/src/commands.rs index 3d79d885c..98bd05063 100644 --- a/wezterm-gui/src/commands.rs +++ b/wezterm-gui/src/commands.rs @@ -1,6 +1,6 @@ use crate::inputmap::InputMap; use config::keyassignment::*; -use config::{ConfigHandle, DeferredKeyCode}; +use config::{ConfigHandle, window::WindowLevel, DeferredKeyCode}; use mux::domain::DomainState; use mux::Mux; use ordered_float::NotNan; @@ -681,15 +681,32 @@ pub fn derive_command_from_key_assignment(action: &KeyAssignment) -> Option CommandDef { - brief: "Always on Top".into(), + ToggleAlwaysOnTop => CommandDef { + brief: "Toggle always on Top".into(), doc: "Toggles the window between floating and non-floating states to stay on top of other windows.".into(), keys: vec![], args: &[ArgType::ActiveWindow], + menubar: &["Window"], + icon: None, + + }, + ToggleAlwaysOnBottom => CommandDef { + brief: "Toggle always on Bottom".into(), + doc: "Toggles the window to remain behind all other windows.".into(), + keys: vec![], + args: &[ArgType::ActiveWindow], + menubar: &["Window"], + icon: None, + }, + SetWindowLevel(WindowLevel::AlwaysOnTop) => CommandDef { + brief: "Always on Top".into(), + doc: "Set the window level to be on top of other windows.".into(), + keys: vec![], + args: &[ArgType::ActiveWindow], menubar: &["Window", "Level"], icon: None, }, - SetWindowLevel(SetWindowLevelLevel::Normal) => CommandDef { + SetWindowLevel(WindowLevel::Normal) => CommandDef { brief: "Normal".into(), doc: "Set window level to normal".into(), keys: vec![], @@ -697,9 +714,9 @@ pub fn derive_command_from_key_assignment(action: &KeyAssignment) -> Option CommandDef { + SetWindowLevel(WindowLevel::AlwaysOnBottom) => CommandDef { brief: "Always on Bottom".into(), - doc: "Toggles the window to remain behind all other windows.".into(), + doc: "Set window to remain behind all other windows.".into(), keys: vec![], args: &[ArgType::ActiveWindow], menubar: &["Window", "Level"], @@ -2041,9 +2058,12 @@ fn compute_default_actions() -> Vec { // ----------------- Window ToggleFullScreen, - SetWindowLevel(SetWindowLevelLevel::AlwaysOnBottom), - SetWindowLevel(SetWindowLevelLevel::Normal), - SetWindowLevel(SetWindowLevelLevel::AlwaysOnTop), + ToggleAlwaysOnTop, + ToggleAlwaysOnBottom, + + SetWindowLevel(WindowLevel::AlwaysOnBottom), + SetWindowLevel(WindowLevel::Normal), + SetWindowLevel(WindowLevel::AlwaysOnTop), Hide, Search(Pattern::CurrentSelectionOrEmptyString), diff --git a/wezterm-gui/src/termwindow/mod.rs b/wezterm-gui/src/termwindow/mod.rs index 99f04acd0..648f76eda 100644 --- a/wezterm-gui/src/termwindow/mod.rs +++ b/wezterm-gui/src/termwindow/mod.rs @@ -30,11 +30,12 @@ use ::window::*; use anyhow::{anyhow, ensure, Context}; use config::keyassignment::{ KeyAssignment, PaneDirection, Pattern, PromptInputLine, QuickSelectArguments, - RotationDirection, SpawnCommand, SplitSize, SetWindowLevelLevel, + RotationDirection, SpawnCommand, SplitSize, }; use config::{ configuration, AudibleBell, ConfigHandle, Dimension, DimensionContext, FrontEndSelection, GeometryOrigin, GuiPosition, TermConfig, WindowCloseConfirmation, + window::WindowLevel }; use lfucache::*; use mlua::{FromLua, UserData, UserDataFields}; @@ -2507,29 +2508,71 @@ impl TermWindow { ToggleFullScreen => { self.window.as_ref().unwrap().toggle_fullscreen(); } + ToggleAlwaysOnTop => { + let window = self.window.clone().unwrap(); + let current_level = self.window_state.as_window_level(); + + match current_level { + WindowLevel::AlwaysOnTop => { + self.window_state -= WindowState::ALWAYS_ON_TOP; + window.set_window_level(WindowLevel::Normal); + } + WindowLevel::AlwaysOnBottom => { + self.window_state -= WindowState::ALWAYS_ON_BOTTOM; + self.window_state = self.window_state | WindowState::ALWAYS_ON_TOP; + window.set_window_level(WindowLevel::AlwaysOnTop); + } + WindowLevel::Normal => { + self.window_state = self.window_state | WindowState::ALWAYS_ON_TOP; + window.set_window_level(WindowLevel::AlwaysOnTop); + } + } + } + ToggleAlwaysOnBottom => { + let window = self.window.clone().unwrap(); + let current_level = self.window_state.as_window_level(); + + match current_level { + WindowLevel::AlwaysOnTop => { + self.window_state -= WindowState::ALWAYS_ON_TOP; + self.window_state = self.window_state | WindowState::ALWAYS_ON_BOTTOM; + window.set_window_level(WindowLevel::AlwaysOnBottom); + } + WindowLevel::AlwaysOnBottom => { + self.window_state -= WindowState::ALWAYS_ON_BOTTOM; + window.set_window_level(WindowLevel::Normal); + } + WindowLevel::Normal => { + self.window_state = self.window_state | WindowState::ALWAYS_ON_BOTTOM; + window.set_window_level(WindowLevel::AlwaysOnBottom); + } + } + } SetWindowLevel(level) => { let window = self.window.clone().unwrap(); - let is_always_on_top = self.window_state.intersects(WindowState::ALWAYS_ON_TOP); - let is_always_on_bottom = self.window_state.intersects(WindowState::ALWAYS_ON_BOTTOM); + let current_level = self.window_state.as_window_level(); - if is_always_on_top { - self.window_state -= WindowState::ALWAYS_ON_TOP; - } - - if is_always_on_bottom { - self.window_state -= WindowState::ALWAYS_ON_BOTTOM; + // reset level state if needed + match current_level { + WindowLevel::AlwaysOnTop => { + self.window_state -= WindowState::ALWAYS_ON_TOP; + } + WindowLevel::AlwaysOnBottom => { + self.window_state -= WindowState::ALWAYS_ON_BOTTOM; + } + _ => {} } match level { - SetWindowLevelLevel::AlwaysOnTop => { + WindowLevel::AlwaysOnTop => { window.set_window_level(WindowLevel::AlwaysOnTop); self.window_state = self.window_state | WindowState::ALWAYS_ON_TOP; } - SetWindowLevelLevel::AlwaysOnBottom => { + WindowLevel::AlwaysOnBottom => { window.set_window_level(WindowLevel::AlwaysOnBottom); self.window_state = self.window_state | WindowState::ALWAYS_ON_BOTTOM; } - SetWindowLevelLevel::Normal => { + WindowLevel::Normal => { window.set_window_level(WindowLevel::Normal); } } diff --git a/window/src/lib.rs b/window/src/lib.rs index d3ccd2ec5..0ffe87bc8 100644 --- a/window/src/lib.rs +++ b/window/src/lib.rs @@ -1,6 +1,6 @@ use async_trait::async_trait; use bitflags::bitflags; -use config::{ConfigHandle, Dimension, GeometryOrigin}; +use config::{ConfigHandle, window::WindowLevel, Dimension, GeometryOrigin}; use promise::Future; use std::any::Any; use std::path::PathBuf; @@ -71,12 +71,6 @@ pub enum MouseCursor { SizeLeftRight, } -#[derive(Debug)] -pub enum WindowLevel { - AlwaysOnBottom = -1, - Normal = 0, - AlwaysOnTop = 3, -} /// Represents the preferred appearance of the windowing /// environment. @@ -132,6 +126,16 @@ impl WindowState { pub fn can_paint(self) -> bool { !self.contains(Self::HIDDEN) } + + pub fn as_window_level(self) -> WindowLevel { + if self.contains(Self::ALWAYS_ON_TOP) { + WindowLevel::AlwaysOnTop + } else if self.contains(Self::ALWAYS_ON_BOTTOM) { + WindowLevel::AlwaysOnBottom + } else { + WindowLevel::Normal + } + } } #[derive(Debug, Clone)] diff --git a/window/src/os/macos/window.rs b/window/src/os/macos/window.rs index 95bc4f3ae..459e8ccc2 100644 --- a/window/src/os/macos/window.rs +++ b/window/src/os/macos/window.rs @@ -8,7 +8,7 @@ use crate::connection::ConnectionOps; use crate::os::macos::menu::{MenuItem, RepresentedItem}; use crate::parameters::{Border, Parameters, TitleBar}; use crate::{ - Clipboard, WindowLevel, Connection, DeadKeyStatus, Dimensions, Handled, KeyCode, KeyEvent, Modifiers, + Clipboard, Connection, DeadKeyStatus, Dimensions, Handled, KeyCode, KeyEvent, Modifiers, MouseButtons, MouseCursor, MouseEvent, MouseEventKind, MousePress, Point, RawKeyEvent, Rect, RequestedWindowGeometry, ResolvedGeometry, ScreenPoint, Size, ULength, WindowDecorations, WindowEvent, WindowEventSender, WindowOps, WindowState, @@ -26,7 +26,7 @@ use cocoa::foundation::{ NSArray, NSAutoreleasePool, NSFastEnumeration, NSInteger, NSNotFound, NSPoint, NSRect, NSSize, NSUInteger, }; -use config::ConfigHandle; +use config::{ConfigHandle, window::WindowLevel}; use core_foundation::base::{CFTypeID, TCFType}; use core_foundation::bundle::{CFBundleGetBundleWithIdentifier, CFBundleGetFunctionPointerForName}; use core_foundation::data::{CFData, CFDataGetBytePtr, CFDataRef};