use super::base_helper::{from_utf16, to_utf16};
use super::high_dpi;
use std::{mem, ptr};
use winapi::ctypes::c_int;
use winapi::shared::minwindef::{LPARAM, LRESULT, UINT, WPARAM};
use winapi::shared::windef::{HFONT, HMENU, HWND};
use winapi::um::winuser::WM_USER;
#[cfg(feature = "rich-textbox")]
use winapi::um::winuser::WNDCLASSEXW;
pub const NOTICE_MESSAGE: UINT = WM_USER + 100;
pub const NWG_INIT: UINT = WM_USER + 101;
pub const NWG_TRAY: UINT = WM_USER + 102;
pub const NWG_TIMER_TICK: UINT = WM_USER + 103;
pub const NWG_TIMER_STOP: UINT = WM_USER + 104;
#[cfg(feature = "rich-textbox")]
pub fn get_class_info(hwnd: HWND) -> Result<WNDCLASSEXW, ()> {
use winapi::shared::ntdef::WCHAR;
use winapi::um::libloaderapi::GetModuleHandleW;
use winapi::um::winuser::{GetClassInfoExW, GetClassNameW};
unsafe {
let mut info: WNDCLASSEXW = mem::zeroed();
let hinst = GetModuleHandleW(ptr::null_mut());
let mut class_name_raw: [WCHAR; 100] = [0; 100];
let count = GetClassNameW(hwnd, class_name_raw.as_mut_ptr(), 100) as usize;
if count == 0 {
return Err(());
}
let result = GetClassInfoExW(hinst, class_name_raw.as_ptr(), &mut info);
match result == 0 {
true => Err(()),
false => Ok(info),
}
}
}
#[cfg(feature = "rich-textbox")]
pub fn get_background_color(hwnd: HWND) -> Result<[u8; 3], ()> {
use winapi::um::wingdi::{
GetBValue, GetGValue, GetObjectW, GetRValue, GetStockObject, LOGBRUSH,
};
use winapi::um::winuser::GetSysColorBrush;
match get_class_info(hwnd) {
Ok(info) => unsafe {
let brush = {
let stock_handle = info.hbrBackground as usize as i32;
let stock = GetStockObject(info.hbrBackground as usize as i32);
match stock.is_null() {
true => info.hbrBackground,
false => {
if stock_handle > 0 {
GetSysColorBrush(stock_handle - 1)
} else {
GetSysColorBrush(0)
}
}
}
};
let mut brush_data: LOGBRUSH = mem::zeroed();
GetObjectW(
brush as _,
mem::size_of::<LOGBRUSH>() as _,
&mut brush_data as *mut LOGBRUSH as _,
);
let col = brush_data.lbColor;
Ok([GetRValue(col), GetGValue(col), GetBValue(col)])
},
Err(_) => Err(()),
}
}
pub fn destroy_window(hwnd: HWND) {
use winapi::um::winuser::{DestroyWindow, SetParent};
iterate_window_children(hwnd, |child| unsafe {
set_window_visibility(child, false);
SetParent(child, ptr::null_mut());
});
unsafe {
DestroyWindow(hwnd);
}
}
pub fn destroy_menu_item(parent: HMENU, item_id: u32) {
use winapi::um::winuser::{DeleteMenu, GetMenuItemCount, GetMenuItemID, MF_BYPOSITION};
unsafe {
let count = GetMenuItemCount(parent);
let mut index = 0;
while index < count {
let id = GetMenuItemID(parent, index);
match id == item_id {
true => {
DeleteMenu(parent, index as u32, MF_BYPOSITION);
index = count;
}
false => {
index += 1;
}
}
}
}
}
pub fn destroy_menu(menu: HMENU) {
use winapi::um::winuser::DestroyMenu;
unsafe {
DestroyMenu(menu);
}
}
pub fn iterate_window_children<F>(hwnd_parent: HWND, cb: F)
where
F: FnMut(HWND) -> (),
{
use winapi::shared::minwindef::BOOL;
use winapi::um::winuser::EnumChildWindows;
struct EnumChildData<F> {
parent: HWND,
callback: F,
}
unsafe extern "system" fn enum_child<F>(hwnd: HWND, p: LPARAM) -> BOOL
where
F: FnMut(HWND) -> (),
{
let enum_data_ptr = p as *mut EnumChildData<F>;
let enum_data = unsafe { &mut *enum_data_ptr };
if get_window_parent(hwnd) == enum_data.parent {
(enum_data.callback)(hwnd);
};
1
}
unsafe {
let mut data = EnumChildData {
parent: hwnd_parent,
callback: cb,
};
EnumChildWindows(
hwnd_parent,
Some(enum_child::<F>),
&mut data as *mut EnumChildData<F> as _,
);
}
}
#[cfg(any(feature = "timer", feature = "animation-timer", feature = "notice"))]
pub fn window_valid(hwnd: HWND) -> bool {
use winapi::um::winuser::IsWindow;
unsafe { IsWindow(hwnd) != 0 }
}
pub fn get_window_parent(hwnd: HWND) -> HWND {
use winapi::um::winuser::GetParent;
unsafe { GetParent(hwnd) }
}
pub fn get_window_font(handle: HWND) -> HFONT {
use winapi::um::winuser::WM_GETFONT;
send_message(handle, WM_GETFONT, 0, 0) as HFONT
}
pub fn maximize_window(handle: HWND) {
use winapi::um::winuser::{SW_MAXIMIZE, ShowWindow};
unsafe {
ShowWindow(handle, SW_MAXIMIZE);
}
}
pub fn minimize_window(handle: HWND) {
use winapi::um::winuser::{SW_MINIMIZE, ShowWindow};
unsafe {
ShowWindow(handle, SW_MINIMIZE);
}
}
pub fn restore_window(handle: HWND) {
use winapi::um::winuser::{SW_RESTORE, ShowWindow};
unsafe {
ShowWindow(handle, SW_RESTORE);
}
}
pub fn set_window_font(handle: HWND, font_handle: Option<HFONT>, redraw: bool) {
use winapi::um::winuser::SendMessageW;
use winapi::um::winuser::WM_SETFONT;
let font_handle = font_handle.unwrap_or(ptr::null_mut());
unsafe { SendMessageW(handle, WM_SETFONT, font_handle as WPARAM, redraw as LPARAM) };
}
#[cfg(feature = "timer")]
pub fn kill_timer(hwnd: HWND, id: u32) {
use winapi::shared::basetsd::UINT_PTR;
use winapi::um::winuser::KillTimer;
unsafe {
KillTimer(hwnd, id as UINT_PTR);
}
}
#[cfg(feature = "timer")]
pub fn start_timer(hwnd: HWND, id: u32, interval: u32) {
use winapi::shared::basetsd::UINT_PTR;
use winapi::um::winuser::SetTimer;
unsafe {
SetTimer(hwnd, id as UINT_PTR, interval, None);
}
}
pub fn get_style(handle: HWND) -> UINT {
use ::winapi::um::winuser::GWL_STYLE;
get_window_long(handle, GWL_STYLE) as UINT
}
#[cfg(any(feature = "list-view", feature = "progress-bar"))]
pub fn set_style(handle: HWND, style: u32) {
use ::winapi::um::winuser::GWL_STYLE;
set_window_long(handle, GWL_STYLE, style as usize);
}
pub fn send_message(hwnd: HWND, msg: UINT, w: WPARAM, l: LPARAM) -> LRESULT {
unsafe { ::winapi::um::winuser::SendMessageW(hwnd, msg, w, l) }
}
pub fn post_message(hwnd: HWND, msg: UINT, w: WPARAM, l: LPARAM) {
unsafe { ::winapi::um::winuser::PostMessageW(hwnd, msg, w, l) };
}
pub fn set_focus(handle: HWND) {
unsafe { ::winapi::um::winuser::SetFocus(handle) };
}
pub fn get_focus(handle: HWND) -> bool {
unsafe { ::winapi::um::winuser::GetFocus() == handle }
}
pub fn get_window_text(handle: HWND) -> String {
use winapi::um::winuser::{GetWindowTextLengthW, GetWindowTextW};
let buffer_size = unsafe { GetWindowTextLengthW(handle) as usize + 1 };
if buffer_size == 0 {
return String::new();
}
let mut buffer: Vec<u16> = vec![0; buffer_size];
if unsafe { GetWindowTextW(handle, buffer.as_mut_ptr(), buffer_size as c_int) } == 0 {
String::new()
} else {
from_utf16(&buffer[..])
}
}
pub fn set_window_text<'a>(handle: HWND, text: &'a str) {
use winapi::um::winuser::SetWindowTextW;
let text = to_utf16(text);
unsafe { SetWindowTextW(handle, text.as_ptr()) };
}
pub fn set_window_position(handle: HWND, x: i32, y: i32) {
use winapi::um::winuser::SetWindowPos;
use winapi::um::winuser::{SWP_NOACTIVATE, SWP_NOOWNERZORDER, SWP_NOSIZE, SWP_NOZORDER};
let (x, y) = high_dpi::logical_to_physical(x, y);
unsafe {
SetWindowPos(
handle,
ptr::null_mut(),
x as c_int,
y as c_int,
0,
0,
SWP_NOZORDER | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER,
)
};
}
pub fn set_window_after(handle: HWND, after: Option<HWND>) {
use winapi::um::winuser::SetWindowPos;
use winapi::um::winuser::{
HWND_TOP, SWP_NOACTIVATE, SWP_NOMOVE, SWP_NOOWNERZORDER, SWP_NOSIZE,
};
let after_handle = match after {
None => HWND_TOP,
Some(w) => w,
};
unsafe {
SetWindowPos(
handle,
after_handle,
0,
0,
0,
0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOOWNERZORDER,
)
};
}
pub fn get_window_position(handle: HWND) -> (i32, i32) {
use winapi::shared::windef::{POINT, RECT};
use winapi::um::winuser::{GetParent, GetWindowRect, ScreenToClient};
unsafe {
let mut r: RECT = mem::zeroed();
GetWindowRect(handle, &mut r);
let parent = GetParent(handle);
let (x, y) = if !parent.is_null() {
let mut pt = POINT {
x: r.left,
y: r.top,
};
ScreenToClient(parent, &mut pt);
(pt.x as i32, pt.y as i32)
} else {
(r.left as i32, r.top as i32)
};
high_dpi::physical_to_logical(x, y)
}
}
pub fn set_window_size(handle: HWND, w: u32, h: u32, fix: bool) {
use winapi::shared::windef::RECT;
use winapi::um::winuser::{AdjustWindowRectEx, GetWindowLongW, SetWindowPos};
use winapi::um::winuser::{
GWL_EXSTYLE, GWL_STYLE, SWP_NOACTIVATE, SWP_NOCOPYBITS, SWP_NOMOVE, SWP_NOOWNERZORDER,
SWP_NOZORDER,
};
let (mut w, mut h) = high_dpi::logical_to_physical(w as i32, h as i32);
if fix {
let flags = unsafe { GetWindowLongW(handle, GWL_STYLE) as u32 };
let ex_flags = unsafe { GetWindowLongW(handle, GWL_EXSTYLE) as u32 };
let mut rect = RECT {
left: 0,
top: 0,
right: w,
bottom: h,
};
unsafe { AdjustWindowRectEx(&mut rect, flags, 0, ex_flags) };
w = rect.right - rect.left;
h = rect.bottom - rect.top;
}
unsafe {
SetWindowPos(
handle,
ptr::null_mut(),
0,
0,
w,
h,
SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOOWNERZORDER,
)
};
}
pub fn get_window_size(handle: HWND) -> (u32, u32) {
get_window_size_impl(handle, false)
}
#[allow(unused)]
pub fn get_window_physical_size(handle: HWND) -> (u32, u32) {
get_window_size_impl(handle, true)
}
fn get_window_size_impl(handle: HWND, return_physical: bool) -> (u32, u32) {
use winapi::shared::windef::RECT;
use winapi::um::winuser::GetClientRect;
let mut r: RECT = unsafe { mem::zeroed() };
unsafe { GetClientRect(handle, &mut r) };
let (w, h) = if return_physical {
(r.right, r.bottom)
} else {
high_dpi::physical_to_logical(r.right, r.bottom)
};
(w as u32, h as u32)
}
pub fn set_window_visibility(handle: HWND, visible: bool) {
use winapi::um::winuser::ShowWindow;
use winapi::um::winuser::{SW_HIDE, SW_SHOW};
let visible = if visible { SW_SHOW } else { SW_HIDE };
unsafe { ShowWindow(handle, visible) };
}
pub fn get_window_visibility(handle: HWND) -> bool {
use winapi::um::winuser::IsWindowVisible;
unsafe { IsWindowVisible(handle) != 0 }
}
pub fn get_window_enabled(handle: HWND) -> bool {
use winapi::um::winuser::{GWL_STYLE, WS_DISABLED};
let style = get_window_long(handle, GWL_STYLE) as UINT;
(style & WS_DISABLED) != WS_DISABLED
}
pub fn set_window_enabled(handle: HWND, enabled: bool) {
use winapi::um::winuser::{GWL_STYLE, WS_DISABLED};
use winapi::um::winuser::{InvalidateRect, UpdateWindow};
let old_style = get_window_long(handle, GWL_STYLE) as usize;
if enabled {
set_window_long(handle, GWL_STYLE, old_style & (!WS_DISABLED as usize));
} else {
set_window_long(handle, GWL_STYLE, old_style | (WS_DISABLED as usize));
}
unsafe {
InvalidateRect(handle, ptr::null(), 1);
UpdateWindow(handle);
}
}
#[cfg(feature = "tabs")]
pub fn get_window_class_name(handle: HWND) -> String {
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use winapi::shared::ntdef::WCHAR;
use winapi::um::winuser::GetClassNameW;
let mut class_name_raw: Vec<WCHAR> = Vec::with_capacity(100);
unsafe { class_name_raw.set_len(100) };
let count = unsafe { GetClassNameW(handle, class_name_raw.as_mut_ptr(), 100) as usize };
OsString::from_wide(&class_name_raw[..count])
.into_string()
.unwrap_or("".to_string())
}
#[cfg(target_pointer_width = "64")]
use winapi::shared::basetsd::LONG_PTR;
#[cfg(target_pointer_width = "32")]
use winapi::shared::ntdef::LONG;
#[inline(always)]
#[cfg(target_pointer_width = "64")]
pub fn get_window_long(handle: HWND, index: c_int) -> LONG_PTR {
unsafe { ::winapi::um::winuser::GetWindowLongPtrW(handle, index) }
}
#[inline(always)]
#[cfg(target_pointer_width = "32")]
pub fn get_window_long(handle: HWND, index: c_int) -> LONG {
unsafe { ::winapi::um::winuser::GetWindowLongW(handle, index) }
}
#[inline(always)]
#[cfg(target_pointer_width = "64")]
pub fn set_window_long(handle: HWND, index: c_int, v: usize) {
unsafe {
::winapi::um::winuser::SetWindowLongPtrW(handle, index, v as LONG_PTR);
}
}
#[inline(always)]
#[cfg(target_pointer_width = "32")]
pub fn set_window_long(handle: HWND, index: c_int, v: usize) {
unsafe {
::winapi::um::winuser::SetWindowLongW(handle, index, v as LONG);
}
}
pub struct DeferredWindowPositioner {
handle: winapi::um::winuser::HDWP,
}
impl DeferredWindowPositioner {
const MEM_FAIL: &'static str = "Insufficient system resources";
pub fn new(item_count: i32) -> Result<DeferredWindowPositioner, &'static str> {
use ::winapi::um::winuser::BeginDeferWindowPos;
let handle = unsafe { BeginDeferWindowPos(item_count) };
if handle.is_null() {
Err(DeferredWindowPositioner::MEM_FAIL)
} else {
Ok(DeferredWindowPositioner { handle })
}
}
pub fn defer_pos(
&mut self,
hwnd: HWND,
hwnd_insertafter: HWND,
x: i32,
y: i32,
cx: i32,
cy: i32,
) -> Result<(), &'static str> {
use ::winapi::um::winuser::DeferWindowPos;
let handle =
unsafe { DeferWindowPos(self.handle, hwnd, hwnd_insertafter, x, y, cx, cy, 0) };
self.handle = handle;
if handle.is_null() {
Err(DeferredWindowPositioner::MEM_FAIL)
} else {
Ok(())
}
}
pub fn end(self) {} }
impl std::ops::Drop for DeferredWindowPositioner {
fn drop(&mut self) {
use ::winapi::um::winuser::EndDeferWindowPos;
if !self.handle.is_null() {
unsafe { EndDeferWindowPos(self.handle) };
}
}
}