Skip to content

Commit

Permalink
refactor(windows-rs): use "wide" fns uniformly
Browse files Browse the repository at this point in the history
This commit builds on @EBNull's comment shedding light on the uses of
the -A and -W functions in the Win32 API, and standardizes the calling
of the -W functions across the project.

Since UTF-16 String handling is a bit lacking in the Rust standard
library, I have pulled in the widestring crate to use the
from_slice_truncate fn to automagically remove all of the trailing null
chars when handling values returned from the various Win32 -W fns.

Comment ref: 657ac44#r135643553
  • Loading branch information
LGUG2Z committed Dec 24, 2023
1 parent e221d96 commit cf86b2c
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 57 deletions.
7 changes: 7 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions komorebi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ windows-implement = { workspace = true }
windows = { workspace = true }
color-eyre = { workspace = true }
dirs = { workspace = true }
widestring = "1"

[features]
deadlock_detection = []
26 changes: 13 additions & 13 deletions komorebi/src/border.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ use std::sync::atomic::Ordering;
use std::time::Duration;

use color_eyre::Result;
use windows::core::PCSTR;
use windows::core::PCWSTR;
use windows::Win32::Foundation::HWND;
use windows::Win32::UI::WindowsAndMessaging::DispatchMessageA;
use windows::Win32::UI::WindowsAndMessaging::FindWindowA;
use windows::Win32::UI::WindowsAndMessaging::GetMessageA;
use windows::Win32::UI::WindowsAndMessaging::DispatchMessageW;
use windows::Win32::UI::WindowsAndMessaging::FindWindowW;
use windows::Win32::UI::WindowsAndMessaging::GetMessageW;
use windows::Win32::UI::WindowsAndMessaging::CS_HREDRAW;
use windows::Win32::UI::WindowsAndMessaging::CS_VREDRAW;
use windows::Win32::UI::WindowsAndMessaging::MSG;
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSA;
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSW;

use komorebi_core::Rect;

Expand Down Expand Up @@ -43,11 +43,11 @@ impl Border {
}

pub fn create(name: &str) -> Result<()> {
let name = format!("{name}\0");
let name: Vec<u16> = format!("{name}\0").encode_utf16().collect();
let instance = WindowsApi::module_handle_w()?;
let class_name = PCSTR(name.as_ptr());
let class_name = PCWSTR(name.as_ptr());
let brush = WindowsApi::create_solid_brush(TRANSPARENCY_COLOUR);
let window_class = WNDCLASSA {
let window_class = WNDCLASSW {
hInstance: instance.into(),
lpszClassName: class_name,
style: CS_HREDRAW | CS_VREDRAW,
Expand All @@ -56,18 +56,18 @@ impl Border {
..Default::default()
};

let _atom = WindowsApi::register_class_a(&window_class)?;
let _atom = WindowsApi::register_class_w(&window_class)?;

let name_cl = name.clone();
std::thread::spawn(move || -> Result<()> {
let hwnd = WindowsApi::create_border_window(PCSTR(name_cl.as_ptr()), instance)?;
let hwnd = WindowsApi::create_border_window(PCWSTR(name_cl.as_ptr()), instance)?;
let border = Self::from(hwnd);

let mut message = MSG::default();

unsafe {
while GetMessageA(&mut message, border.hwnd(), 0, 0).into() {
DispatchMessageA(&message);
while GetMessageW(&mut message, border.hwnd(), 0, 0).into() {
DispatchMessageW(&message);
std::thread::sleep(Duration::from_millis(10));
}
}
Expand All @@ -77,7 +77,7 @@ impl Border {

let mut hwnd = HWND(0);
while hwnd == HWND(0) {
hwnd = unsafe { FindWindowA(PCSTR(name.as_ptr()), PCSTR::null()) };
hwnd = unsafe { FindWindowW(PCWSTR(name.as_ptr()), PCWSTR::null()) };
}

BORDER_HWND.store(hwnd.0, Ordering::SeqCst);
Expand Down
26 changes: 13 additions & 13 deletions komorebi/src/hidden.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@ use std::sync::atomic::Ordering;
use std::time::Duration;

use color_eyre::Result;
use windows::core::PCSTR;
use windows::core::PCWSTR;
use windows::Win32::Foundation::HWND;
use windows::Win32::UI::WindowsAndMessaging::DispatchMessageA;
use windows::Win32::UI::WindowsAndMessaging::FindWindowA;
use windows::Win32::UI::WindowsAndMessaging::GetMessageA;
use windows::Win32::UI::WindowsAndMessaging::DispatchMessageW;
use windows::Win32::UI::WindowsAndMessaging::FindWindowW;
use windows::Win32::UI::WindowsAndMessaging::GetMessageW;
use windows::Win32::UI::WindowsAndMessaging::CS_HREDRAW;
use windows::Win32::UI::WindowsAndMessaging::CS_VREDRAW;
use windows::Win32::UI::WindowsAndMessaging::MSG;
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSA;
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSW;

use crate::windows_callbacks;
use crate::WindowsApi;
Expand All @@ -34,11 +34,11 @@ impl Hidden {
}

pub fn create(name: &str) -> Result<()> {
let name = format!("{name}\0");
let name: Vec<u16> = format!("{name}\0").encode_utf16().collect();
let instance = WindowsApi::module_handle_w()?;
let class_name = PCSTR(name.as_ptr());
let class_name = PCWSTR(name.as_ptr());
let brush = WindowsApi::create_solid_brush(TRANSPARENCY_COLOUR);
let window_class = WNDCLASSA {
let window_class = WNDCLASSW {
hInstance: instance.into(),
lpszClassName: class_name,
style: CS_HREDRAW | CS_VREDRAW,
Expand All @@ -47,18 +47,18 @@ impl Hidden {
..Default::default()
};

let _atom = WindowsApi::register_class_a(&window_class)?;
let _atom = WindowsApi::register_class_w(&window_class)?;

let name_cl = name.clone();
std::thread::spawn(move || -> Result<()> {
let hwnd = WindowsApi::create_hidden_window(PCSTR(name_cl.as_ptr()), instance)?;
let hwnd = WindowsApi::create_hidden_window(PCWSTR(name_cl.as_ptr()), instance)?;
let hidden = Self::from(hwnd);

let mut message = MSG::default();

unsafe {
while GetMessageA(&mut message, hidden.hwnd(), 0, 0).into() {
DispatchMessageA(&message);
while GetMessageW(&mut message, hidden.hwnd(), 0, 0).into() {
DispatchMessageW(&message);
std::thread::sleep(Duration::from_millis(10));
}
}
Expand All @@ -68,7 +68,7 @@ impl Hidden {

let mut hwnd = HWND(0);
while hwnd == HWND(0) {
hwnd = unsafe { FindWindowA(PCSTR(name.as_ptr()), PCSTR::null()) };
hwnd = unsafe { FindWindowW(PCWSTR(name.as_ptr()), PCWSTR::null()) };
}

HIDDEN_HWND.store(hwnd.0, Ordering::SeqCst);
Expand Down
47 changes: 23 additions & 24 deletions komorebi/src/windows_api.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
use std::collections::VecDeque;
use std::convert::TryFrom;
use std::ffi::c_void;
use std::ffi::OsString;
use std::os::windows::ffi::OsStringExt;
use std::sync::atomic::Ordering;

use color_eyre::eyre::anyhow;
use color_eyre::eyre::Error;
use color_eyre::Result;
use widestring::U16CStr;
use windows::core::Result as WindowsCrateResult;
use windows::core::PCSTR;
use windows::core::PCWSTR;
use windows::core::PWSTR;
use windows::Win32::Foundation::CloseHandle;
use windows::Win32::Foundation::BOOL;
Expand All @@ -30,13 +29,13 @@ use windows::Win32::Graphics::Dwm::DWM_CLOAKED_APP;
use windows::Win32::Graphics::Dwm::DWM_CLOAKED_INHERITED;
use windows::Win32::Graphics::Dwm::DWM_CLOAKED_SHELL;
use windows::Win32::Graphics::Gdi::CreateSolidBrush;
use windows::Win32::Graphics::Gdi::EnumDisplayDevicesA;
use windows::Win32::Graphics::Gdi::EnumDisplayDevicesW;
use windows::Win32::Graphics::Gdi::EnumDisplayMonitors;
use windows::Win32::Graphics::Gdi::GetMonitorInfoW;
use windows::Win32::Graphics::Gdi::InvalidateRect;
use windows::Win32::Graphics::Gdi::MonitorFromPoint;
use windows::Win32::Graphics::Gdi::MonitorFromWindow;
use windows::Win32::Graphics::Gdi::DISPLAY_DEVICEA;
use windows::Win32::Graphics::Gdi::DISPLAY_DEVICEW;
use windows::Win32::Graphics::Gdi::HBRUSH;
use windows::Win32::Graphics::Gdi::HDC;
use windows::Win32::Graphics::Gdi::HMONITOR;
Expand Down Expand Up @@ -69,7 +68,7 @@ use windows::Win32::UI::Shell::Common::DEVICE_SCALE_FACTOR;
use windows::Win32::UI::Shell::GetScaleFactorForMonitor;
use windows::Win32::UI::WindowsAndMessaging::AllowSetForegroundWindow;
use windows::Win32::UI::WindowsAndMessaging::BringWindowToTop;
use windows::Win32::UI::WindowsAndMessaging::CreateWindowExA;
use windows::Win32::UI::WindowsAndMessaging::CreateWindowExW;
use windows::Win32::UI::WindowsAndMessaging::EnumWindows;
use windows::Win32::UI::WindowsAndMessaging::GetCursorPos;
use windows::Win32::UI::WindowsAndMessaging::GetDesktopWindow;
Expand All @@ -85,7 +84,7 @@ use windows::Win32::UI::WindowsAndMessaging::IsWindow;
use windows::Win32::UI::WindowsAndMessaging::IsWindowVisible;
use windows::Win32::UI::WindowsAndMessaging::PostMessageW;
use windows::Win32::UI::WindowsAndMessaging::RealGetWindowClassW;
use windows::Win32::UI::WindowsAndMessaging::RegisterClassA;
use windows::Win32::UI::WindowsAndMessaging::RegisterClassW;
use windows::Win32::UI::WindowsAndMessaging::SetCursorPos;
use windows::Win32::UI::WindowsAndMessaging::SetForegroundWindow;
use windows::Win32::UI::WindowsAndMessaging::SetLayeredWindowAttributes;
Expand Down Expand Up @@ -120,7 +119,7 @@ use windows::Win32::UI::WindowsAndMessaging::SYSTEM_PARAMETERS_INFO_ACTION;
use windows::Win32::UI::WindowsAndMessaging::SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS;
use windows::Win32::UI::WindowsAndMessaging::WINDOW_LONG_PTR_INDEX;
use windows::Win32::UI::WindowsAndMessaging::WM_CLOSE;
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSA;
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSW;
use windows::Win32::UI::WindowsAndMessaging::WNDENUMPROC;
use windows::Win32::UI::WindowsAndMessaging::WS_DISABLED;
use windows::Win32::UI::WindowsAndMessaging::WS_EX_LAYERED;
Expand Down Expand Up @@ -242,21 +241,21 @@ impl WindowsApi {

pub fn enum_display_devices(
index: u32,
lp_device: Option<*const u8>,
) -> Result<DISPLAY_DEVICEA> {
lp_device: Option<*const u16>,
) -> Result<DISPLAY_DEVICEW> {
#[allow(clippy::option_if_let_else)]
let lp_device = match lp_device {
None => PCSTR::null(),
Some(lp_device) => PCSTR(lp_device),
None => PCWSTR::null(),
Some(lp_device) => PCWSTR(lp_device),
};

let mut display_device = DISPLAY_DEVICEA {
cb: u32::try_from(std::mem::size_of::<DISPLAY_DEVICEA>())?,
let mut display_device = DISPLAY_DEVICEW {
cb: u32::try_from(std::mem::size_of::<DISPLAY_DEVICEW>())?,
..Default::default()
};

match unsafe {
EnumDisplayDevicesA(
EnumDisplayDevicesW(
lp_device,
index,
std::ptr::addr_of_mut!(display_device),
Expand Down Expand Up @@ -690,10 +689,10 @@ impl WindowsApi {

pub fn monitor(hmonitor: isize) -> Result<Monitor> {
let ex_info = Self::monitor_info_w(HMONITOR(hmonitor))?;
let name = OsString::from_wide(&ex_info.szDevice);
let name = name
let name = U16CStr::from_slice_truncate(&ex_info.szDevice)
.expect("monitor name was not a valid u16 c string")
.to_ustring()
.to_string_lossy()
.replace('\u{0000}', "")
.trim_start_matches(r"\\.\")
.to_string();

Expand Down Expand Up @@ -799,8 +798,8 @@ impl WindowsApi {
unsafe { CreateSolidBrush(COLORREF(colour)) }
}

pub fn register_class_a(window_class: &WNDCLASSA) -> Result<u16> {
Result::from(WindowsResult::from(unsafe { RegisterClassA(window_class) }))
pub fn register_class_w(window_class: &WNDCLASSW) -> Result<u16> {
Result::from(WindowsResult::from(unsafe { RegisterClassW(window_class) }))
}

pub fn scale_factor_for_monitor(hmonitor: isize) -> Result<DEVICE_SCALE_FACTOR> {
Expand Down Expand Up @@ -828,9 +827,9 @@ impl WindowsApi {
.process()
}

pub fn create_border_window(name: PCSTR, instance: HMODULE) -> Result<isize> {
pub fn create_border_window(name: PCWSTR, instance: HMODULE) -> Result<isize> {
unsafe {
let hwnd = CreateWindowExA(
let hwnd = CreateWindowExW(
WS_EX_TOOLWINDOW | WS_EX_LAYERED,
name,
name,
Expand Down Expand Up @@ -862,9 +861,9 @@ impl WindowsApi {
Ok(())
}

pub fn create_hidden_window(name: PCSTR, instance: HMODULE) -> Result<isize> {
pub fn create_hidden_window(name: PCWSTR, instance: HMODULE) -> Result<isize> {
unsafe {
CreateWindowExA(
CreateWindowExW(
WS_EX_NOACTIVATE,
name,
name,
Expand Down
20 changes: 13 additions & 7 deletions komorebi/src/windows_callbacks.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use std::collections::VecDeque;
use std::sync::atomic::Ordering;
use widestring::U16CStr;

use windows::Win32::Foundation::BOOL;
use windows::Win32::Foundation::COLORREF;
Expand Down Expand Up @@ -78,19 +79,24 @@ pub extern "system" fn enum_display_monitor(
if let Ok(mut m) = WindowsApi::monitor(hmonitor.0) {
#[allow(clippy::cast_possible_truncation)]
if let Ok(d) = WindowsApi::enum_display_devices(current_index as u32, None) {
let name = String::from_utf8_lossy(&d.DeviceName);
let clean_name = name
.replace('\u{0000}', "")
let name = U16CStr::from_slice_truncate(d.DeviceName.as_ref())
.expect("display device name was not a valid u16 c string")
.to_ustring()
.to_string_lossy()
.trim_start_matches(r"\\.\")
.to_string();

if clean_name.eq(m.name()) {
if name.eq(m.name()) {
if let Ok(device) = WindowsApi::enum_display_devices(0, Some(d.DeviceName.as_ptr()))
{
let id = String::from_utf8_lossy(&device.DeviceID);
let clean_id = id.replace('\u{0000}', "");
let id = U16CStr::from_slice_truncate(device.DeviceID.as_ref())
.expect("display device id was not a valid u16 c string")
.to_ustring()
.to_string_lossy()
.trim_start_matches(r"\\?\")
.to_string();

let mut split: Vec<_> = clean_id.split('#').collect();
let mut split: Vec<_> = id.split('#').collect();
split.remove(0);
split.remove(split.len() - 1);

Expand Down

0 comments on commit cf86b2c

Please sign in to comment.