diff --git a/Cargo.lock b/Cargo.lock index 84de928ca..a6d16e67f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5018,6 +5018,7 @@ dependencies = [ "wezterm-font", "wezterm-input-types", "winapi 0.3.9", + "windows", "winreg 0.6.2", "x11", "xcb 0.9.0", diff --git a/assets/windows/manifest.manifest b/assets/windows/manifest.manifest index 66a892704..c6042ce46 100644 --- a/assets/windows/manifest.manifest +++ b/assets/windows/manifest.manifest @@ -1,9 +1,43 @@ - - + + PerMonitorV2 + + + + + + + + + + + + + + + + + + + diff --git a/wezterm-gui/build.rs b/wezterm-gui/build.rs index a0b5971e7..7ef7b9877 100644 --- a/wezterm-gui/build.rs +++ b/wezterm-gui/build.rs @@ -103,8 +103,8 @@ fn main() { #include // 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 diff --git a/wezterm-gui/src/termwindow/mod.rs b/wezterm-gui/src/termwindow/mod.rs index fac803f07..307800176 100644 --- a/wezterm-gui/src/termwindow/mod.rs +++ b/wezterm-gui/src/termwindow/mod.rs @@ -285,6 +285,7 @@ pub struct TermWindow { pub window: Option, pub config: ConfigHandle, pub config_overrides: serde_json::Value, + os_parameters: Option, /// When we most recently received keyboard focus focused: Option, fonts: Rc, @@ -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); diff --git a/wezterm-gui/src/termwindow/render.rs b/wezterm-gui/src/termwindow/render.rs index 499642d40..3d4951488 100644 --- a/wezterm-gui/src/termwindow/render.rs +++ b/wezterm-gui/src/termwindow/render.rs @@ -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(()) } diff --git a/window/Cargo.toml b/window/Cargo.toml index fa1002b8e..85dad682f 100644 --- a/window/Cargo.toml +++ b/window/Cargo.toml @@ -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" diff --git a/window/src/lib.rs b/window/src/lib.rs index 20cf87747..3161e905a 100644 --- a/window/src/lib.rs +++ b/window/src/lib.rs @@ -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; +pub type LengthF = euclid::Length; pub type Rect = euclid::Rect; pub type RectF = euclid::Rect; pub type Size = euclid::Size2D; @@ -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> { + Ok(None) } } diff --git a/window/src/os/mod.rs b/window/src/os/mod.rs index f16ed5019..26b132349 100644 --- a/window/src/os/mod.rs +++ b/window/src/os/mod.rs @@ -16,3 +16,5 @@ pub use x_and_wayland::*; pub mod macos; #[cfg(target_os = "macos")] pub use self::macos::*; + +pub mod parameters; diff --git a/window/src/os/parameters.rs b/window/src/os/parameters.rs new file mode 100644 index 000000000..b7b1ffa70 --- /dev/null +++ b/window/src/os/parameters.rs @@ -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, + 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, // If present, the application should draw it +} diff --git a/window/src/os/windows/extra_constants.rs b/window/src/os/windows/extra_constants.rs new file mode 100644 index 000000000..bd48583de --- /dev/null +++ b/window/src/os/windows/extra_constants.rs @@ -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; diff --git a/window/src/os/windows/mod.rs b/window/src/os/windows/mod.rs index fb9ecd9b8..7b844638c 100644 --- a/window/src/os/windows/mod.rs +++ b/window/src/os/windows/mod.rs @@ -1,5 +1,6 @@ pub mod connection; pub mod event; +mod extra_constants; mod keycodes; mod wgl; pub mod window; diff --git a/window/src/os/windows/window.rs b/window/src/os/windows/window.rs index 0945aaf9c..1b62bcc3e 100644 --- a/window/src/os/windows/window.rs +++ b/window/src/os/windows/window.rs @@ -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>, /// Fraction of mouse scroll @@ -62,6 +70,7 @@ pub(crate) struct WindowInner { dead_pending: Option<(Modifiers, u32)>, saved_placement: Option, 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, ) -> anyhow::Result { - // 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,72 +735,129 @@ 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; - - unsafe fn populate_log_font(hwnd: HWND, hdc: HDC) -> Option { - 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 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 !theme.is_null() { - let res = GetThemeFont( - theme, - hdc, - HP_HEADERITEM, - HIS_NORMAL, - TMT_CAPTIONFONT, - &mut log_font, - ); - if res == S_OK { - CloseThemeData(theme); - return Some(log_font); - } - } + fn get_os_parameters(&self, config: &ConfigHandle) -> anyhow::Result> { + let hwnd = self.0 .0; + if hwnd.is_null() { + return Err(anyhow::anyhow!("HWND is null")); + } - let res = GetThemeSysFont(theme, TMT_CAPTIONFONT, &mut log_font); - if !theme.is_null() { - CloseThemeData(theme); - } + let has_focus = !unsafe { GetFocus() }.is_null(); + let is_maximized = window_is_maximized(hwnd); - if res == S_OK { - Some(log_font) + let is_full_screen = unsafe { + let mut mi = MONITORINFO { + cbSize: std::mem::size_of::() as u32, + ..Default::default() + }; + 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 { - None + false } - } - unsafe { - let hwnd = self.0 .0; + }; + + let title_font = unsafe { let hdc = GetDC(hwnd); - let result = match populate_log_font(hwnd, hdc) { - Some(lf) => wezterm_font::locator::gdi::parse_log_font(&lf, hdc).ok(), + 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::("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 { + let mut log_font = LOGFONTW::default(); + let theme = OpenThemeData(hwnd, wide_string("HEADER").as_ptr()); + if !theme.is_null() { + let res = GetThemeFont( + theme, + hdc, + extra_constants::HP_HEADERITEM, + extra_constants::HIS_NORMAL, + extra_constants::TMT_CAPTIONFONT, + &mut log_font, + ); + if res == S_OK { + CloseThemeData(theme); + return Some(log_font); } } + + let res = GetThemeSysFont(theme, extra_constants::TMT_CAPTIONFONT, &mut log_font); + if !theme.is_null() { + CloseThemeData(theme); + } + + if res == S_OK { + Some(log_font) + } else { + None + } } /// 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 { + 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 { + 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::() 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::() 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 { None } +fn dispatch_appearance_changed(hwnd: HWND) -> Option { + 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 { + 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 { let mut should_paint = false; let mut should_pump = false; @@ -974,10 +1224,12 @@ unsafe fn wm_set_focus( _lparam: LPARAM, ) -> Option { 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 { 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, } }