mirror of
https://github.com/wez/wezterm.git
synced 2024-12-22 21:01:36 +03:00
Improve RESIZE window_decoration on Windows
This commit is contained in:
parent
32bf0d281e
commit
b036bb3b05
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -5018,6 +5018,7 @@ dependencies = [
|
||||
"wezterm-font",
|
||||
"wezterm-input-types",
|
||||
"winapi 0.3.9",
|
||||
"windows",
|
||||
"winreg 0.6.2",
|
||||
"x11",
|
||||
"xcb 0.9.0",
|
||||
|
@ -1,9 +1,43 @@
|
||||
<?xml version='1.0' encoding='UTF-8' standalone='yes'?>
|
||||
<assembly xmlns="urn:schemas-microsoft-com:asm.v1"
|
||||
manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<assembly
|
||||
manifestVersion="1.0"
|
||||
xmlns="urn:schemas-microsoft-com:asm.v1"
|
||||
xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"
|
||||
>
|
||||
<asmv3:application>
|
||||
<asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
|
||||
<dpiAwareness>PerMonitorV2</dpiAwareness>
|
||||
</asmv3:windowsSettings>
|
||||
</asmv3:application>
|
||||
<dependency>
|
||||
<dependentAssembly>
|
||||
<assemblyIdentity
|
||||
type="win32"
|
||||
name="Microsoft.Windows.Common-Controls"
|
||||
version="6.0.0.0"
|
||||
processorArchitecture="*"
|
||||
publicKeyToken="6595b64144ccf1df"
|
||||
language="*"
|
||||
/>
|
||||
</dependentAssembly>
|
||||
</dependency>
|
||||
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
|
||||
<application>
|
||||
<!-- Windows 10 and Windows 11 -->
|
||||
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
|
||||
</application>
|
||||
</compatibility>
|
||||
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
|
||||
<security>
|
||||
<requestedPrivileges>
|
||||
<!--
|
||||
UAC settings:
|
||||
- app should run at same integrity level as calling process
|
||||
- app does not need to manipulate windows belonging to
|
||||
higher-integrity-level processes
|
||||
-->
|
||||
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
|
||||
</requestedPrivileges>
|
||||
</security>
|
||||
</trustInfo>
|
||||
</assembly>
|
||||
|
@ -103,8 +103,8 @@ fn main() {
|
||||
#include <winres.h>
|
||||
// This ID is coupled with code in window/src/os/windows/window.rs
|
||||
#define IDI_ICON 0x101
|
||||
1 RT_MANIFEST "{win}\\manifest.manifest"
|
||||
IDI_ICON ICON "{win}\\terminal.ico"
|
||||
APP_MANIFEST RT_MANIFEST "{win}\\manifest.manifest"
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 1,0,0,0
|
||||
PRODUCTVERSION 1,0,0,0
|
||||
|
@ -285,6 +285,7 @@ pub struct TermWindow {
|
||||
pub window: Option<Window>,
|
||||
pub config: ConfigHandle,
|
||||
pub config_overrides: serde_json::Value,
|
||||
os_parameters: Option<parameters::Parameters>,
|
||||
/// When we most recently received keyboard focus
|
||||
focused: Option<Instant>,
|
||||
fonts: Rc<FontConfiguration>,
|
||||
@ -446,6 +447,8 @@ impl TermWindow {
|
||||
}
|
||||
}
|
||||
|
||||
self.os_parameters = window.get_os_parameters(&self.config).unwrap_or(None);
|
||||
|
||||
window.show();
|
||||
|
||||
if self.render_state.is_none() {
|
||||
@ -690,6 +693,7 @@ impl TermWindow {
|
||||
|
||||
let myself = Self {
|
||||
config_subscription: None,
|
||||
os_parameters: None,
|
||||
gl: None,
|
||||
window: None,
|
||||
window_background,
|
||||
@ -1432,6 +1436,14 @@ impl TermWindow {
|
||||
};
|
||||
|
||||
if let Some(window) = self.window.as_ref().map(|w| w.clone()) {
|
||||
self.os_parameters = match window.get_os_parameters(&config) {
|
||||
Ok(os_parameters) => os_parameters,
|
||||
Err(_) => {
|
||||
log::warn!("Error while getting OS parameters");
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
self.apply_scale_change(&dimensions, self.fonts.get_font_scale(), &window);
|
||||
self.apply_dimensions(&dimensions, None, &window);
|
||||
window.config_did_change(&config);
|
||||
|
@ -920,6 +920,58 @@ impl super::TermWindow {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn paint_window_borders(&mut self) -> anyhow::Result<()> {
|
||||
if let Some(ref os_params) = self.os_parameters {
|
||||
if let Some(ref border_dimensions) = os_params.border_dimensions {
|
||||
let gl_state = self.render_state.as_ref().unwrap();
|
||||
let vb = &gl_state.vb[1];
|
||||
let mut vb_mut = vb.current_vb_mut();
|
||||
let mut layer1 = vb.map(&mut vb_mut);
|
||||
|
||||
let height = self.dimensions.pixel_height as f32;
|
||||
let width = self.dimensions.pixel_width as f32;
|
||||
|
||||
let border_top = border_dimensions.top.get() as f32;
|
||||
if border_top > 0.0 {
|
||||
self.filled_rectangle(
|
||||
&mut layer1,
|
||||
euclid::rect(0.0, 0.0, width, border_top),
|
||||
border_dimensions.color,
|
||||
)?;
|
||||
}
|
||||
|
||||
let border_left = border_dimensions.left.get() as f32;
|
||||
if border_left > 0.0 {
|
||||
self.filled_rectangle(
|
||||
&mut layer1,
|
||||
euclid::rect(0.0, 0.0, border_left, height),
|
||||
border_dimensions.color,
|
||||
)?;
|
||||
}
|
||||
|
||||
let border_bottom = border_dimensions.bottom.get() as f32;
|
||||
if border_bottom > 0.0 {
|
||||
self.filled_rectangle(
|
||||
&mut layer1,
|
||||
euclid::rect(0.0, height - border_bottom, width, height),
|
||||
border_dimensions.color,
|
||||
)?;
|
||||
}
|
||||
|
||||
let border_right = border_dimensions.right.get() as f32;
|
||||
if border_right > 0.0 {
|
||||
self.filled_rectangle(
|
||||
&mut layer1,
|
||||
euclid::rect(width - border_right, 0.0, width, height),
|
||||
border_dimensions.color,
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn paint_pane_opengl(
|
||||
&mut self,
|
||||
pos: &PositionedPane,
|
||||
@ -1557,6 +1609,8 @@ impl super::TermWindow {
|
||||
self.paint_tab_bar()?;
|
||||
}
|
||||
|
||||
self.paint_window_borders()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -47,18 +47,22 @@ wezterm-font = { path = "../wezterm-font" }
|
||||
wezterm-input-types = { path = "../wezterm-input-types" }
|
||||
|
||||
[target."cfg(windows)".dependencies]
|
||||
clipboard-win = "2.2"
|
||||
shared_library = "0.1"
|
||||
winapi = { version = "0.3", features = [
|
||||
"dwmapi",
|
||||
"handleapi",
|
||||
"imm",
|
||||
"libloaderapi",
|
||||
"synchapi",
|
||||
"sysinfoapi",
|
||||
"winerror",
|
||||
"winuser",
|
||||
]}
|
||||
windows = { version="0.33.0", features = [
|
||||
"UI_ViewManagement",
|
||||
]}
|
||||
winreg = "0.6"
|
||||
clipboard-win = "2.2"
|
||||
shared_library = "0.1"
|
||||
|
||||
[target.'cfg(all(unix, not(target_os = "macos")))'.dependencies]
|
||||
dirs-next = "2.0"
|
||||
|
@ -1,5 +1,6 @@
|
||||
use async_trait::async_trait;
|
||||
use bitflags::bitflags;
|
||||
use config::ConfigHandle;
|
||||
use promise::Future;
|
||||
use std::any::Any;
|
||||
use std::rc::Rc;
|
||||
@ -50,6 +51,8 @@ pub struct Dimensions {
|
||||
pub dpi: usize,
|
||||
}
|
||||
|
||||
pub type Length = euclid::Length<isize, PixelUnit>;
|
||||
pub type LengthF = euclid::Length<f32, PixelUnit>;
|
||||
pub type Rect = euclid::Rect<isize, PixelUnit>;
|
||||
pub type RectF = euclid::Rect<f32, PixelUnit>;
|
||||
pub type Size = euclid::Size2D<isize, PixelUnit>;
|
||||
@ -281,7 +284,10 @@ pub trait WindowOps {
|
||||
/// environment.
|
||||
fn set_resize_increments(&self, _x: u16, _y: u16) {}
|
||||
|
||||
fn get_title_font_and_point_size(&self) -> Option<(wezterm_font::parser::ParsedFont, f64)> {
|
||||
None
|
||||
fn get_os_parameters(
|
||||
&self,
|
||||
_config: &ConfigHandle,
|
||||
) -> anyhow::Result<Option<os::parameters::Parameters>> {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
@ -16,3 +16,5 @@ pub use x_and_wayland::*;
|
||||
pub mod macos;
|
||||
#[cfg(target_os = "macos")]
|
||||
pub use self::macos::*;
|
||||
|
||||
pub mod parameters;
|
||||
|
24
window/src/os/parameters.rs
Normal file
24
window/src/os/parameters.rs
Normal file
@ -0,0 +1,24 @@
|
||||
use wezterm_color_types::LinearRgba;
|
||||
use wezterm_font::parser::ParsedFont;
|
||||
|
||||
use crate::Length;
|
||||
|
||||
pub struct TitleBar {
|
||||
pub padding_left: Length,
|
||||
pub padding_right: Length,
|
||||
pub height: Option<Length>,
|
||||
pub font_and_size: Option<(ParsedFont, f64)>,
|
||||
}
|
||||
|
||||
pub struct Border {
|
||||
pub top: Length,
|
||||
pub left: Length,
|
||||
pub bottom: Length,
|
||||
pub right: Length,
|
||||
pub color: LinearRgba,
|
||||
}
|
||||
|
||||
pub struct Parameters {
|
||||
pub title_bar: TitleBar,
|
||||
pub border_dimensions: Option<Border>, // If present, the application should draw it
|
||||
}
|
7
window/src/os/windows/extra_constants.rs
Normal file
7
window/src/os/windows/extra_constants.rs
Normal file
@ -0,0 +1,7 @@
|
||||
use winapi::um::winuser::WM_USER;
|
||||
|
||||
pub const TMT_CAPTIONFONT: i32 = 801;
|
||||
pub const HP_HEADERITEM: i32 = 1;
|
||||
pub const HIS_NORMAL: i32 = 1;
|
||||
|
||||
pub const UM_APPEARANCE_CHANGED: u32 = WM_USER + 1;
|
@ -1,5 +1,6 @@
|
||||
pub mod connection;
|
||||
pub mod event;
|
||||
mod extra_constants;
|
||||
mod keycodes;
|
||||
mod wgl;
|
||||
pub mod window;
|
||||
|
@ -1,9 +1,11 @@
|
||||
use super::*;
|
||||
use crate::connection::ConnectionOps;
|
||||
use crate::parameters::Parameters;
|
||||
use crate::{
|
||||
Appearance, Clipboard, DeadKeyStatus, Dimensions, Handled, KeyCode, KeyEvent, Modifiers,
|
||||
MouseButtons, MouseCursor, MouseEvent, MouseEventKind, MousePress, Point, RawKeyEvent, Rect,
|
||||
ScreenPoint, WindowDecorations, WindowEvent, WindowEventSender, WindowOps, WindowState,
|
||||
Appearance, Clipboard, DeadKeyStatus, Dimensions, Handled, KeyCode, KeyEvent, Length,
|
||||
Modifiers, MouseButtons, MouseCursor, MouseEvent, MouseEventKind, MousePress, Point,
|
||||
RawKeyEvent, Rect, ScreenPoint, WindowDecorations, WindowEvent, WindowEventSender, WindowOps,
|
||||
WindowState,
|
||||
};
|
||||
use anyhow::{bail, Context};
|
||||
use async_trait::async_trait;
|
||||
@ -22,6 +24,7 @@ use std::io::{self, Error as IoError};
|
||||
use std::os::windows::ffi::OsStringExt;
|
||||
use std::ptr::{null, null_mut};
|
||||
use std::rc::Rc;
|
||||
use wezterm_color_types::LinearRgba;
|
||||
use wezterm_font::FontConfiguration;
|
||||
use winapi::shared::minwindef::*;
|
||||
use winapi::shared::ntdef::*;
|
||||
@ -29,11 +32,15 @@ use winapi::shared::windef::*;
|
||||
use winapi::shared::winerror::S_OK;
|
||||
use winapi::um::imm::*;
|
||||
use winapi::um::libloaderapi::GetModuleHandleW;
|
||||
use winapi::um::sysinfoapi::{GetTickCount, GetVersionExW};
|
||||
use winapi::um::uxtheme::{
|
||||
CloseThemeData, GetThemeFont, GetThemeSysFont, OpenThemeData, SetWindowTheme,
|
||||
};
|
||||
use winapi::um::wingdi::LOGFONTW;
|
||||
use winapi::um::wingdi::{LOGFONTW, MAKEPOINTS};
|
||||
use winapi::um::winnt::OSVERSIONINFOW;
|
||||
use winapi::um::winuser::*;
|
||||
use windows::UI::Color as WUIColor;
|
||||
use windows::UI::ViewManagement::{UIColorType, UISettings};
|
||||
use winreg::enums::HKEY_CURRENT_USER;
|
||||
use winreg::RegKey;
|
||||
|
||||
@ -51,6 +58,7 @@ unsafe impl Sync for HWindow {}
|
||||
pub(crate) struct WindowInner {
|
||||
/// Non-owning reference to the window handle
|
||||
hwnd: HWindow,
|
||||
is_win10: bool,
|
||||
events: WindowEventSender,
|
||||
gl_state: Option<Rc<glium::backend::Context>>,
|
||||
/// Fraction of mouse scroll
|
||||
@ -62,6 +70,7 @@ pub(crate) struct WindowInner {
|
||||
dead_pending: Option<(Modifiers, u32)>,
|
||||
saved_placement: Option<WINDOWPLACEMENT>,
|
||||
track_mouse_leave: bool,
|
||||
last_resize_type: WPARAM,
|
||||
|
||||
keyboard_info: KeyboardLayoutInfo,
|
||||
appearance: Appearance,
|
||||
@ -72,6 +81,10 @@ pub(crate) struct WindowInner {
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
|
||||
pub struct Window(HWindow);
|
||||
|
||||
fn wuicolor_to_linearrgba(color: WUIColor) -> LinearRgba {
|
||||
LinearRgba::with_srgba(color.R, color.G, color.B, 255)
|
||||
}
|
||||
|
||||
fn rect_width(r: &RECT) -> i32 {
|
||||
r.right - r.left
|
||||
}
|
||||
@ -266,14 +279,19 @@ fn apply_decoration_immediate(hwnd: HWND, decorations: WindowDecorations) {
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOOWNERZORDER | SWP_FRAMECHANGED,
|
||||
SWP_NOACTIVATE
|
||||
| SWP_NOMOVE
|
||||
| SWP_NOSIZE
|
||||
| SWP_NOZORDER
|
||||
| SWP_NOOWNERZORDER
|
||||
| SWP_FRAMECHANGED,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn decorations_to_style(decorations: WindowDecorations) -> u32 {
|
||||
if decorations == WindowDecorations::RESIZE {
|
||||
WS_THICKFRAME
|
||||
WS_OVERLAPPEDWINDOW
|
||||
} else if decorations == WindowDecorations::TITLE {
|
||||
WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
|
||||
} else if decorations == WindowDecorations::NONE {
|
||||
@ -294,12 +312,6 @@ impl Window {
|
||||
height: usize,
|
||||
lparam: *const RefCell<WindowInner>,
|
||||
) -> anyhow::Result<HWND> {
|
||||
// Jamming this in here; it should really live in the application manifest,
|
||||
// but having it here means that we don't have to create a manifest
|
||||
unsafe {
|
||||
SetProcessDpiAwarenessContext(DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2);
|
||||
}
|
||||
|
||||
let class_name = wide_string(class_name);
|
||||
let h_inst = unsafe { GetModuleHandleW(null()) };
|
||||
let class = WNDCLASSW {
|
||||
@ -404,8 +416,10 @@ impl Window {
|
||||
None => config::configuration(),
|
||||
};
|
||||
let appearance = get_appearance();
|
||||
|
||||
let inner = Rc::new(RefCell::new(WindowInner {
|
||||
hwnd: HWindow(null_mut()),
|
||||
is_win10: is_win10(),
|
||||
appearance,
|
||||
events,
|
||||
gl_state: None,
|
||||
@ -417,6 +431,7 @@ impl Window {
|
||||
dead_pending: None,
|
||||
saved_placement: None,
|
||||
track_mouse_leave: false,
|
||||
last_resize_type: SIZE_RESTORED,
|
||||
config: config.clone(),
|
||||
}));
|
||||
|
||||
@ -569,6 +584,10 @@ impl WindowInner {
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
promise::spawn::spawn(async move {
|
||||
PostMessageW(hwnd, extra_constants::UM_APPEARANCE_CHANGED, 0, 0);
|
||||
})
|
||||
.detach();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -716,42 +735,111 @@ impl WindowOps for Window {
|
||||
clipboard_win::set_clipboard_string(&text).ok();
|
||||
}
|
||||
|
||||
fn get_title_font_and_point_size(&self) -> Option<(wezterm_font::parser::ParsedFont, f64)> {
|
||||
const TMT_CAPTIONFONT: i32 = 801;
|
||||
const HP_HEADERITEM: i32 = 1;
|
||||
const HIS_NORMAL: i32 = 1;
|
||||
fn get_os_parameters(&self, config: &ConfigHandle) -> anyhow::Result<Option<Parameters>> {
|
||||
let hwnd = self.0 .0;
|
||||
if hwnd.is_null() {
|
||||
return Err(anyhow::anyhow!("HWND is null"));
|
||||
}
|
||||
|
||||
unsafe fn populate_log_font(hwnd: HWND, hdc: HDC) -> Option<LOGFONTW> {
|
||||
let mut log_font = LOGFONTW {
|
||||
lfHeight: 0,
|
||||
lfWidth: 0,
|
||||
lfEscapement: 0,
|
||||
lfOrientation: 0,
|
||||
lfWeight: 0,
|
||||
lfItalic: 0,
|
||||
lfUnderline: 0,
|
||||
lfStrikeOut: 0,
|
||||
lfCharSet: 0,
|
||||
lfOutPrecision: 0,
|
||||
lfClipPrecision: 0,
|
||||
lfQuality: 0,
|
||||
lfPitchAndFamily: 0,
|
||||
lfFaceName: [0u16; 32],
|
||||
let has_focus = !unsafe { GetFocus() }.is_null();
|
||||
let is_maximized = window_is_maximized(hwnd);
|
||||
|
||||
let is_full_screen = unsafe {
|
||||
let mut mi = MONITORINFO {
|
||||
cbSize: std::mem::size_of::<MONITORINFO>() as u32,
|
||||
..Default::default()
|
||||
};
|
||||
let theme = OpenThemeData(
|
||||
hwnd,
|
||||
[
|
||||
'H' as u16, 'E' as u16, 'A' as u16, 'D' as u16, 'E' as u16, 'R' as u16, 0u16,
|
||||
]
|
||||
.as_ptr(),
|
||||
);
|
||||
if GetMonitorInfoW(MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY), &mut mi)
|
||||
== winapi::shared::minwindef::TRUE
|
||||
{
|
||||
let mut client_rect = RECT::default();
|
||||
if GetClientRect(hwnd, &mut client_rect) == winapi::shared::minwindef::TRUE {
|
||||
client_rect.right >= mi.rcMonitor.right - mi.rcMonitor.left
|
||||
&& client_rect.bottom >= mi.rcMonitor.bottom - mi.rcMonitor.top
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
false
|
||||
}
|
||||
};
|
||||
|
||||
let title_font = unsafe {
|
||||
let hdc = GetDC(hwnd);
|
||||
if hdc.is_null() {
|
||||
return Err(anyhow::anyhow!("Could not get device context"));
|
||||
}
|
||||
let result = match get_title_log_font(hwnd, hdc) {
|
||||
Some(lf) => Some(wezterm_font::locator::gdi::parse_log_font(&lf, hdc)?),
|
||||
None => None,
|
||||
};
|
||||
ReleaseDC(hwnd, hdc);
|
||||
result
|
||||
};
|
||||
|
||||
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
|
||||
let use_accent = hkcu
|
||||
.open_subkey("SOFTWARE\\Microsoft\\Windows\\DWM")?
|
||||
.get_value::<u32, _>("ColorPrevalence")?;
|
||||
let settings = UISettings::new()?;
|
||||
let top_border_color = if has_focus {
|
||||
if use_accent == 1 {
|
||||
wuicolor_to_linearrgba(settings.GetColorValue(UIColorType::Accent)?)
|
||||
} else {
|
||||
if is_win10() {
|
||||
LinearRgba(0.01, 0.01, 0.01, 0.67)
|
||||
} else {
|
||||
LinearRgba(0.026, 0.026, 0.026, 0.5)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if is_win10() {
|
||||
LinearRgba(0.024, 0.024, 0.024, 0.5)
|
||||
} else {
|
||||
LinearRgba(0.028, 0.028, 0.028, 0.5)
|
||||
}
|
||||
};
|
||||
|
||||
const BASE_BORDER: Length = Length::new(0);
|
||||
let is_resize = config.window_decorations == WindowDecorations::RESIZE;
|
||||
|
||||
let is_win10 = is_win10();
|
||||
Ok(Some(Parameters {
|
||||
title_bar: crate::parameters::TitleBar {
|
||||
padding_left: Length::new(0),
|
||||
padding_right: Length::new(0),
|
||||
height: None,
|
||||
font_and_size: title_font,
|
||||
},
|
||||
border_dimensions: Some(crate::parameters::Border {
|
||||
top: if is_resize && !is_win10 && !is_maximized && !is_full_screen {
|
||||
BASE_BORDER + Length::new(1)
|
||||
} else {
|
||||
BASE_BORDER
|
||||
},
|
||||
left: BASE_BORDER,
|
||||
bottom: if is_resize && is_win10 && !is_maximized && !is_full_screen {
|
||||
BASE_BORDER + Length::new(2)
|
||||
} else {
|
||||
BASE_BORDER
|
||||
},
|
||||
right: BASE_BORDER,
|
||||
color: top_border_color,
|
||||
}),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn get_title_log_font(hwnd: HWND, hdc: HDC) -> Option<LOGFONTW> {
|
||||
let mut log_font = LOGFONTW::default();
|
||||
let theme = OpenThemeData(hwnd, wide_string("HEADER").as_ptr());
|
||||
if !theme.is_null() {
|
||||
let res = GetThemeFont(
|
||||
theme,
|
||||
hdc,
|
||||
HP_HEADERITEM,
|
||||
HIS_NORMAL,
|
||||
TMT_CAPTIONFONT,
|
||||
extra_constants::HP_HEADERITEM,
|
||||
extra_constants::HIS_NORMAL,
|
||||
extra_constants::TMT_CAPTIONFONT,
|
||||
&mut log_font,
|
||||
);
|
||||
if res == S_OK {
|
||||
@ -760,7 +848,7 @@ impl WindowOps for Window {
|
||||
}
|
||||
}
|
||||
|
||||
let res = GetThemeSysFont(theme, TMT_CAPTIONFONT, &mut log_font);
|
||||
let res = GetThemeSysFont(theme, extra_constants::TMT_CAPTIONFONT, &mut log_font);
|
||||
if !theme.is_null() {
|
||||
CloseThemeData(theme);
|
||||
}
|
||||
@ -770,18 +858,6 @@ impl WindowOps for Window {
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
unsafe {
|
||||
let hwnd = self.0 .0;
|
||||
let hdc = GetDC(hwnd);
|
||||
let result = match populate_log_font(hwnd, hdc) {
|
||||
Some(lf) => wezterm_font::locator::gdi::parse_log_font(&lf, hdc).ok(),
|
||||
None => None,
|
||||
};
|
||||
ReleaseDC(hwnd, hdc);
|
||||
result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Set up bidirectional pointers:
|
||||
@ -817,6 +893,152 @@ unsafe fn wm_ncdestroy(
|
||||
None
|
||||
}
|
||||
|
||||
unsafe fn wm_nccalcsize(hwnd: HWND, _msg: UINT, wparam: WPARAM, lparam: LPARAM) -> Option<LRESULT> {
|
||||
if let Some(inner) = rc_from_hwnd(hwnd) {
|
||||
let inner = inner.borrow_mut();
|
||||
|
||||
if !(wparam == 1 && inner.config.window_decorations == WindowDecorations::RESIZE) {
|
||||
return None;
|
||||
}
|
||||
|
||||
if inner.saved_placement.is_none() {
|
||||
let dpi = GetDpiForWindow(hwnd);
|
||||
let frame_x = GetSystemMetricsForDpi(SM_CXFRAME, dpi);
|
||||
let frame_y = GetSystemMetricsForDpi(SM_CYFRAME, dpi);
|
||||
let padding = GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi);
|
||||
|
||||
let params = (lparam as *mut NCCALCSIZE_PARAMS).as_mut().unwrap();
|
||||
|
||||
let mut requested_client_rect = &mut params.rgrc[0];
|
||||
|
||||
requested_client_rect.right -= frame_x + padding;
|
||||
requested_client_rect.left += frame_x + padding;
|
||||
|
||||
// Handle bugged top window border on Windows 10
|
||||
if inner.is_win10 {
|
||||
if window_is_maximized(hwnd) {
|
||||
requested_client_rect.top += frame_y + padding;
|
||||
requested_client_rect.bottom -= frame_y + padding;
|
||||
} else {
|
||||
requested_client_rect.top += 1;
|
||||
requested_client_rect.bottom -= frame_y - padding;
|
||||
}
|
||||
} else {
|
||||
requested_client_rect.bottom -= frame_y + padding;
|
||||
|
||||
if window_is_maximized(hwnd) {
|
||||
requested_client_rect.top += frame_y + padding;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Some(0);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
unsafe fn wm_nchittest(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM) -> Option<LRESULT> {
|
||||
if let Some(inner) = rc_from_hwnd(hwnd) {
|
||||
let inner = inner.borrow_mut();
|
||||
|
||||
if inner.config.window_decorations != WindowDecorations::RESIZE {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Let the default procedure handle resizing areas
|
||||
let result = DefWindowProcW(hwnd, msg, wparam, lparam);
|
||||
|
||||
if matches!(
|
||||
result,
|
||||
HTNOWHERE
|
||||
| HTRIGHT
|
||||
| HTLEFT
|
||||
| HTTOPLEFT
|
||||
| HTTOP
|
||||
| HTTOPRIGHT
|
||||
| HTBOTTOMRIGHT
|
||||
| HTBOTTOM
|
||||
| HTBOTTOMLEFT
|
||||
) {
|
||||
return Some(result);
|
||||
}
|
||||
|
||||
// The adjustment in NCCALCSIZE messes with the detection
|
||||
// of the top hit area so manually fixing that.
|
||||
let dpi = GetDpiForWindow(hwnd);
|
||||
let frame_x = GetSystemMetricsForDpi(SM_CXFRAME, dpi) as isize;
|
||||
let frame_y = GetSystemMetricsForDpi(SM_CYFRAME, dpi) as isize;
|
||||
let padding = GetSystemMetricsForDpi(SM_CXPADDEDBORDER, dpi) as isize;
|
||||
|
||||
let coords = mouse_coords(lparam);
|
||||
let cursor_point = screen_to_client(hwnd, ScreenPoint::new(coords.x, coords.y));
|
||||
let is_maximized = window_is_maximized(hwnd);
|
||||
|
||||
// check if mouse is in any of the resize areas (HTTOP, HTBOTTOM, etc)
|
||||
|
||||
let mut client_rect = RECT::default();
|
||||
let client_rect_is_valid =
|
||||
GetClientRect(hwnd, &mut client_rect) == winapi::shared::minwindef::TRUE;
|
||||
|
||||
// Since we are eating the bottom window frame to deal with a Windows 10 bug,
|
||||
// we detect resizing in the window client area as a workaround
|
||||
if !is_maximized
|
||||
&& inner.is_win10
|
||||
&& client_rect_is_valid
|
||||
&& cursor_point.y >= (client_rect.bottom as isize) - (frame_y + padding)
|
||||
{
|
||||
if cursor_point.x <= (frame_x + padding) {
|
||||
return Some(HTBOTTOMLEFT);
|
||||
} else if cursor_point.x >= (client_rect.right as isize) - (frame_x + padding) {
|
||||
return Some(HTBOTTOMRIGHT);
|
||||
} else {
|
||||
return Some(HTBOTTOM);
|
||||
}
|
||||
}
|
||||
|
||||
if !is_maximized && cursor_point.y >= 0 && cursor_point.y < frame_y {
|
||||
if cursor_point.x <= (frame_x + padding) {
|
||||
return Some(HTTOPLEFT);
|
||||
} else if cursor_point.x >= (client_rect.right as isize) - (frame_x + padding) {
|
||||
return Some(HTTOPRIGHT);
|
||||
} else {
|
||||
return Some(HTTOP);
|
||||
}
|
||||
}
|
||||
|
||||
return Some(HTCLIENT);
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn window_is_maximized(hwnd: HWND) -> bool {
|
||||
let mut placement = WINDOWPLACEMENT {
|
||||
length: std::mem::size_of::<WINDOWPLACEMENT>() as _,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
if unsafe { GetWindowPlacement(hwnd, &mut placement) } != winapi::shared::minwindef::TRUE {
|
||||
false
|
||||
} else {
|
||||
placement.showCmd == SW_SHOWMAXIMIZED as u32
|
||||
}
|
||||
}
|
||||
|
||||
fn is_win10() -> bool {
|
||||
let osver = OSVERSIONINFOW {
|
||||
dwOSVersionInfoSize: std::mem::size_of::<OSVERSIONINFOW>() as _,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
if unsafe { GetVersionExW(&osver as *const _ as _) } == winapi::shared::minwindef::TRUE {
|
||||
osver.dwBuildNumber < 22000
|
||||
} else {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
/// "Blur behind" is the old vista term for a cool blurring
|
||||
/// effect that the DWM could enable. Subsequent windows
|
||||
/// versions have removed the blurring. We use this call
|
||||
@ -913,6 +1135,17 @@ fn apply_theme(hwnd: HWND) -> Option<LRESULT> {
|
||||
None
|
||||
}
|
||||
|
||||
fn dispatch_appearance_changed(hwnd: HWND) -> Option<LRESULT> {
|
||||
if let Some(inner) = rc_from_hwnd(hwnd) {
|
||||
let mut inner = inner.borrow_mut();
|
||||
let appearance = inner.appearance;
|
||||
inner
|
||||
.events
|
||||
.dispatch(WindowEvent::AppearanceChanged(appearance));
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
unsafe fn wm_enter_exit_size_move(
|
||||
hwnd: HWND,
|
||||
msg: UINT,
|
||||
@ -947,6 +1180,23 @@ unsafe fn wm_windowposchanged(
|
||||
Some(0)
|
||||
}
|
||||
|
||||
unsafe fn wm_sizeraw(hwnd: HWND, _msg: UINT, wparam: WPARAM, _lparam: LPARAM) -> Option<LRESULT> {
|
||||
if wparam == SIZE_RESTORED || wparam == SIZE_MAXIMIZED {
|
||||
if let Some(inner) = rc_from_hwnd(hwnd) {
|
||||
let mut inner = inner.borrow_mut();
|
||||
if inner.last_resize_type != wparam {
|
||||
inner.last_resize_type = wparam;
|
||||
let appearance = inner.appearance;
|
||||
inner
|
||||
.events
|
||||
.dispatch(WindowEvent::AppearanceChanged(appearance));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
unsafe fn wm_size(hwnd: HWND, _msg: UINT, _wparam: WPARAM, _lparam: LPARAM) -> Option<LRESULT> {
|
||||
let mut should_paint = false;
|
||||
let mut should_pump = false;
|
||||
@ -974,10 +1224,12 @@ unsafe fn wm_set_focus(
|
||||
_lparam: LPARAM,
|
||||
) -> Option<LRESULT> {
|
||||
if let Some(inner) = rc_from_hwnd(hwnd) {
|
||||
let mut inner = inner.borrow_mut();
|
||||
inner.events.dispatch(WindowEvent::FocusChanged(true));
|
||||
let appearance = inner.appearance;
|
||||
inner
|
||||
.borrow_mut()
|
||||
.events
|
||||
.dispatch(WindowEvent::FocusChanged(true));
|
||||
.dispatch(WindowEvent::AppearanceChanged(appearance));
|
||||
}
|
||||
None
|
||||
}
|
||||
@ -989,10 +1241,12 @@ unsafe fn wm_kill_focus(
|
||||
_lparam: LPARAM,
|
||||
) -> Option<LRESULT> {
|
||||
if let Some(inner) = rc_from_hwnd(hwnd) {
|
||||
let mut inner = inner.borrow_mut();
|
||||
inner.events.dispatch(WindowEvent::FocusChanged(false));
|
||||
let appearance = inner.appearance;
|
||||
inner
|
||||
.borrow_mut()
|
||||
.events
|
||||
.dispatch(WindowEvent::FocusChanged(false));
|
||||
.dispatch(WindowEvent::AppearanceChanged(appearance));
|
||||
}
|
||||
None
|
||||
}
|
||||
@ -1050,11 +1304,8 @@ fn mods_and_buttons(wparam: WPARAM) -> (Modifiers, MouseButtons) {
|
||||
}
|
||||
|
||||
fn mouse_coords(lparam: LPARAM) -> Point {
|
||||
// Take care to get the signedness correct!
|
||||
let x = (lparam & 0xffff) as u16 as i16 as isize;
|
||||
let y = ((lparam >> 16) & 0xffff) as u16 as i16 as isize;
|
||||
|
||||
Point::new(x, y)
|
||||
let point = MAKEPOINTS(lparam as _);
|
||||
Point::new(point.x as _, point.y as _)
|
||||
}
|
||||
|
||||
fn screen_to_client(hwnd: HWND, point: ScreenPoint) -> Point {
|
||||
@ -1660,7 +1911,6 @@ impl KeyboardLayoutInfo {
|
||||
|
||||
/// Generate a MSG and call TranslateMessage upon it
|
||||
unsafe fn translate_message(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM) {
|
||||
use winapi::um::sysinfoapi::GetTickCount;
|
||||
TranslateMessage(&MSG {
|
||||
hwnd,
|
||||
message: msg,
|
||||
@ -2019,7 +2269,10 @@ unsafe fn do_wnd_proc(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM) ->
|
||||
match msg {
|
||||
WM_NCCREATE => wm_nccreate(hwnd, msg, wparam, lparam),
|
||||
WM_NCDESTROY => wm_ncdestroy(hwnd, msg, wparam, lparam),
|
||||
WM_NCCALCSIZE => wm_nccalcsize(hwnd, msg, wparam, lparam),
|
||||
WM_NCHITTEST => wm_nchittest(hwnd, msg, wparam, lparam),
|
||||
WM_PAINT => wm_paint(hwnd, msg, wparam, lparam),
|
||||
WM_SIZE => wm_sizeraw(hwnd, msg, wparam, lparam),
|
||||
WM_ENTERSIZEMOVE | WM_EXITSIZEMOVE => wm_enter_exit_size_move(hwnd, msg, wparam, lparam),
|
||||
WM_WINDOWPOSCHANGED => wm_windowposchanged(hwnd, msg, wparam, lparam),
|
||||
WM_SETFOCUS => wm_set_focus(hwnd, msg, wparam, lparam),
|
||||
@ -2050,6 +2303,7 @@ unsafe fn do_wnd_proc(hwnd: HWND, msg: UINT, wparam: WPARAM, lparam: LPARAM) ->
|
||||
}
|
||||
None
|
||||
}
|
||||
extra_constants::UM_APPEARANCE_CHANGED => dispatch_appearance_changed(hwnd),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user