mirror of
https://github.com/LGUG2Z/komorebi.git
synced 2026-07-06 21:15:13 +02:00
feat(borders): add border manager module
This commit removes all border-related code from process_command, process_event etc. and centralizes it in the new border_manager module. Instead of trying to figure out where in process_event and process_command we should make border-related changes, a notification gets sent to a channel that border_manager listens to whenever an event or command has finished processing. The border_manager listener, upon receiving a notification, acquires a lock on the WindowManager instance and updates borders for the focused workspace on every monitor; this allows us to centralize all edge case handling within the border_manager listener's loop. Borders on workspaces that lose focus are now destroyed and recreated when those workspaces regain focus, instead of trying to share individual border instances across workspaces. A number of common edge cases that have been addressed in this commit are: * Paused window manager * Floating workspaces * Maximized windows * Fullscreen videos * Monocle containers * Ghost borders on workspace switching * Incorrect focused window border colours Global state related to borders has also been moved into the border_manager module, which also tracks the state of border objects (BORDER_STATE), their rects (RECT_STATE) and their focus kinds (FOCUS_STATE). This allows us to now track multiple borders per-container, enabling unfocused border windows for the first time. Additionally, the Z-Order for border windows is now also configurable. ActiveWindowBorderColours has been expanded to include Unfocused, but in order to not introduce a breaking configuration change for end users, all members of this struct have been made Option<Colour>.
This commit is contained in:
@@ -18,6 +18,8 @@ dirs = "5"
|
|||||||
color-eyre = "0.6"
|
color-eyre = "0.6"
|
||||||
serde_json = { package = "serde_json_lenient", version = "0.1" }
|
serde_json = { package = "serde_json_lenient", version = "0.1" }
|
||||||
sysinfo = "0.30"
|
sysinfo = "0.30"
|
||||||
|
serde = { version = "1", features = ["derive"] }
|
||||||
|
uds_windows = "1"
|
||||||
|
|
||||||
[workspace.dependencies.windows]
|
[workspace.dependencies.windows]
|
||||||
version = "0.54"
|
version = "0.54"
|
||||||
|
|||||||
@@ -218,6 +218,7 @@ pub enum WindowKind {
|
|||||||
Single,
|
Single,
|
||||||
Stack,
|
Stack,
|
||||||
Monocle,
|
Monocle,
|
||||||
|
Unfocused,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(
|
#[derive(
|
||||||
|
|||||||
@@ -1,108 +0,0 @@
|
|||||||
use std::sync::atomic::Ordering;
|
|
||||||
|
|
||||||
use color_eyre::Result;
|
|
||||||
use windows::core::PCWSTR;
|
|
||||||
use windows::Win32::Foundation::HWND;
|
|
||||||
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::WNDCLASSW;
|
|
||||||
|
|
||||||
use crate::window::Window;
|
|
||||||
use crate::windows_callbacks;
|
|
||||||
use crate::WindowsApi;
|
|
||||||
use crate::BORDER_HWND;
|
|
||||||
use crate::BORDER_OFFSET;
|
|
||||||
use crate::BORDER_RECT;
|
|
||||||
use crate::BORDER_WIDTH;
|
|
||||||
use crate::TRANSPARENCY_COLOUR;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
|
||||||
pub struct Border {
|
|
||||||
pub(crate) hwnd: isize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<isize> for Border {
|
|
||||||
fn from(hwnd: isize) -> Self {
|
|
||||||
Self { hwnd }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Border {
|
|
||||||
pub const fn hwnd(self) -> HWND {
|
|
||||||
HWND(self.hwnd)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn create(name: &str) -> Result<()> {
|
|
||||||
let name: Vec<u16> = format!("{name}\0").encode_utf16().collect();
|
|
||||||
let instance = WindowsApi::module_handle_w()?;
|
|
||||||
let class_name = PCWSTR(name.as_ptr());
|
|
||||||
let brush = WindowsApi::create_solid_brush(TRANSPARENCY_COLOUR);
|
|
||||||
let window_class = WNDCLASSW {
|
|
||||||
hInstance: instance.into(),
|
|
||||||
lpszClassName: class_name,
|
|
||||||
style: CS_HREDRAW | CS_VREDRAW,
|
|
||||||
lpfnWndProc: Some(windows_callbacks::border_window),
|
|
||||||
hbrBackground: brush,
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
let _atom = WindowsApi::register_class_w(&window_class)?;
|
|
||||||
|
|
||||||
let name_cl = name.clone();
|
|
||||||
std::thread::spawn(move || -> Result<()> {
|
|
||||||
let hwnd = WindowsApi::create_border_window(PCWSTR(name_cl.as_ptr()), instance)?;
|
|
||||||
let border = Self::from(hwnd);
|
|
||||||
|
|
||||||
let mut message = MSG::default();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
while GetMessageW(&mut message, border.hwnd(), 0, 0).into() {
|
|
||||||
DispatchMessageW(&message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
});
|
|
||||||
|
|
||||||
let mut hwnd = HWND(0);
|
|
||||||
while hwnd == HWND(0) {
|
|
||||||
hwnd = unsafe { FindWindowW(PCWSTR(name.as_ptr()), PCWSTR::null()) };
|
|
||||||
}
|
|
||||||
|
|
||||||
BORDER_HWND.store(hwnd.0, Ordering::SeqCst);
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn hide(self) -> Result<()> {
|
|
||||||
if self.hwnd == 0 {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
WindowsApi::hide_border_window(self.hwnd())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn set_position(self, window: Window, activate: bool) -> Result<()> {
|
|
||||||
if self.hwnd == 0 {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
if !WindowsApi::is_window(self.hwnd()) {
|
|
||||||
Self::create("komorebi-border-window")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut rect = WindowsApi::window_rect(window.hwnd())?;
|
|
||||||
rect.add_padding(-BORDER_OFFSET.load(Ordering::SeqCst));
|
|
||||||
|
|
||||||
let border_width = BORDER_WIDTH.load(Ordering::SeqCst);
|
|
||||||
rect.add_margin(border_width);
|
|
||||||
|
|
||||||
*BORDER_RECT.lock() = rect;
|
|
||||||
|
|
||||||
WindowsApi::position_border_window(self.hwnd(), &rect, activate)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,204 @@
|
|||||||
|
use crate::border_manager::WindowKind;
|
||||||
|
use crate::border_manager::BORDER_OFFSET;
|
||||||
|
use crate::border_manager::BORDER_WIDTH;
|
||||||
|
use crate::border_manager::FOCUSED;
|
||||||
|
use crate::border_manager::FOCUS_STATE;
|
||||||
|
use crate::border_manager::MONOCLE;
|
||||||
|
use crate::border_manager::RECT_STATE;
|
||||||
|
use crate::border_manager::STACK;
|
||||||
|
use crate::border_manager::STYLE;
|
||||||
|
use crate::border_manager::UNFOCUSED;
|
||||||
|
use crate::border_manager::Z_ORDER;
|
||||||
|
use crate::WindowsApi;
|
||||||
|
use crate::WINDOWS_11;
|
||||||
|
|
||||||
|
use komorebi_core::ActiveWindowBorderStyle;
|
||||||
|
use komorebi_core::Rect;
|
||||||
|
|
||||||
|
use std::sync::atomic::Ordering;
|
||||||
|
use std::sync::mpsc;
|
||||||
|
use std::time::Duration;
|
||||||
|
use windows::core::PCWSTR;
|
||||||
|
use windows::Win32::Foundation::COLORREF;
|
||||||
|
use windows::Win32::Foundation::HWND;
|
||||||
|
use windows::Win32::Foundation::LPARAM;
|
||||||
|
use windows::Win32::Foundation::LRESULT;
|
||||||
|
use windows::Win32::Foundation::WPARAM;
|
||||||
|
use windows::Win32::Graphics::Gdi::BeginPaint;
|
||||||
|
use windows::Win32::Graphics::Gdi::CreatePen;
|
||||||
|
use windows::Win32::Graphics::Gdi::EndPaint;
|
||||||
|
use windows::Win32::Graphics::Gdi::InvalidateRect;
|
||||||
|
use windows::Win32::Graphics::Gdi::Rectangle;
|
||||||
|
use windows::Win32::Graphics::Gdi::RoundRect;
|
||||||
|
use windows::Win32::Graphics::Gdi::SelectObject;
|
||||||
|
use windows::Win32::Graphics::Gdi::ValidateRect;
|
||||||
|
use windows::Win32::Graphics::Gdi::PAINTSTRUCT;
|
||||||
|
use windows::Win32::Graphics::Gdi::PS_INSIDEFRAME;
|
||||||
|
use windows::Win32::Graphics::Gdi::PS_SOLID;
|
||||||
|
use windows::Win32::UI::WindowsAndMessaging::DefWindowProcW;
|
||||||
|
use windows::Win32::UI::WindowsAndMessaging::DispatchMessageW;
|
||||||
|
use windows::Win32::UI::WindowsAndMessaging::GetMessageW;
|
||||||
|
use windows::Win32::UI::WindowsAndMessaging::PostQuitMessage;
|
||||||
|
use windows::Win32::UI::WindowsAndMessaging::TranslateMessage;
|
||||||
|
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::WM_DESTROY;
|
||||||
|
use windows::Win32::UI::WindowsAndMessaging::WM_PAINT;
|
||||||
|
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSW;
|
||||||
|
|
||||||
|
pub struct Border {
|
||||||
|
pub hwnd: isize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Border {
|
||||||
|
pub const fn hwnd(&self) -> HWND {
|
||||||
|
HWND(self.hwnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create(id: &str) -> color_eyre::Result<Self> {
|
||||||
|
let name: Vec<u16> = format!("komoborder-{id}\0").encode_utf16().collect();
|
||||||
|
let class_name = PCWSTR(name.as_ptr());
|
||||||
|
|
||||||
|
let h_module = WindowsApi::module_handle_w()?;
|
||||||
|
|
||||||
|
let window_class = WNDCLASSW {
|
||||||
|
hInstance: h_module.into(),
|
||||||
|
lpszClassName: class_name,
|
||||||
|
style: CS_HREDRAW | CS_VREDRAW,
|
||||||
|
lpfnWndProc: Some(Self::callback),
|
||||||
|
hbrBackground: WindowsApi::create_solid_brush(0),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let _ = WindowsApi::register_class_w(&window_class);
|
||||||
|
|
||||||
|
let (hwnd_sender, hwnd_receiver) = mpsc::channel();
|
||||||
|
|
||||||
|
std::thread::spawn(move || -> color_eyre::Result<()> {
|
||||||
|
let hwnd = WindowsApi::create_border_window(PCWSTR(name.as_ptr()), h_module)?;
|
||||||
|
hwnd_sender.send(hwnd)?;
|
||||||
|
|
||||||
|
let mut message = MSG::default();
|
||||||
|
unsafe {
|
||||||
|
while GetMessageW(&mut message, HWND(hwnd), 0, 0).into() {
|
||||||
|
TranslateMessage(&message);
|
||||||
|
DispatchMessageW(&message);
|
||||||
|
std::thread::sleep(Duration::from_millis(10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
hwnd: hwnd_receiver.recv()?,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(&self) -> color_eyre::Result<()> {
|
||||||
|
WindowsApi::destroy_window(self.hwnd())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update(&self, rect: &Rect) -> color_eyre::Result<()> {
|
||||||
|
// Make adjustments to the border
|
||||||
|
let mut rect = *rect;
|
||||||
|
rect.add_margin(BORDER_WIDTH.load(Ordering::SeqCst));
|
||||||
|
rect.add_padding(-BORDER_OFFSET.load(Ordering::SeqCst));
|
||||||
|
|
||||||
|
// Store the border rect so that it can be used by the callback
|
||||||
|
{
|
||||||
|
let mut rects = RECT_STATE.lock();
|
||||||
|
rects.insert(self.hwnd, rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the position of the border
|
||||||
|
WindowsApi::set_border_pos(self.hwnd(), &rect, HWND((*Z_ORDER.lock()).into()))?;
|
||||||
|
|
||||||
|
// Invalidate the rect to trigger the callback to update colours etc.
|
||||||
|
self.invalidate();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn invalidate(&self) {
|
||||||
|
let _ = unsafe { InvalidateRect(self.hwnd(), None, false) };
|
||||||
|
}
|
||||||
|
|
||||||
|
pub extern "system" fn callback(
|
||||||
|
window: HWND,
|
||||||
|
message: u32,
|
||||||
|
wparam: WPARAM,
|
||||||
|
lparam: LPARAM,
|
||||||
|
) -> LRESULT {
|
||||||
|
unsafe {
|
||||||
|
match message {
|
||||||
|
WM_PAINT => {
|
||||||
|
let rects = RECT_STATE.lock();
|
||||||
|
|
||||||
|
// With the rect that we stored in Self::update
|
||||||
|
if let Some(rect) = rects.get(&window.0).copied() {
|
||||||
|
// Grab the focus kind for this border
|
||||||
|
let focus_kind = {
|
||||||
|
FOCUS_STATE
|
||||||
|
.lock()
|
||||||
|
.get(&window.0)
|
||||||
|
.copied()
|
||||||
|
.unwrap_or(WindowKind::Unfocused)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Set up the brush to draw the border
|
||||||
|
let mut ps = PAINTSTRUCT::default();
|
||||||
|
let hdc = BeginPaint(window, &mut ps);
|
||||||
|
let hpen = CreatePen(
|
||||||
|
PS_SOLID | PS_INSIDEFRAME,
|
||||||
|
BORDER_WIDTH.load(Ordering::SeqCst),
|
||||||
|
COLORREF(match focus_kind {
|
||||||
|
WindowKind::Unfocused => UNFOCUSED.load(Ordering::SeqCst),
|
||||||
|
WindowKind::Single => FOCUSED.load(Ordering::SeqCst),
|
||||||
|
WindowKind::Stack => STACK.load(Ordering::SeqCst),
|
||||||
|
WindowKind::Monocle => MONOCLE.load(Ordering::SeqCst),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
|
||||||
|
let hbrush = WindowsApi::create_solid_brush(0);
|
||||||
|
|
||||||
|
// Draw the border
|
||||||
|
SelectObject(hdc, hpen);
|
||||||
|
SelectObject(hdc, hbrush);
|
||||||
|
// TODO(raggi): this is approximately the correct curvature for
|
||||||
|
// the top left of a Windows 11 window (DWMWCP_DEFAULT), but
|
||||||
|
// often the bottom right has a different shape. Furthermore if
|
||||||
|
// the window was made with DWMWCP_ROUNDSMALL then this is the
|
||||||
|
// wrong size. In the future we should read the DWM properties
|
||||||
|
// of windows and attempt to match appropriately.
|
||||||
|
match *STYLE.lock() {
|
||||||
|
ActiveWindowBorderStyle::System => {
|
||||||
|
if *WINDOWS_11 {
|
||||||
|
RoundRect(hdc, 0, 0, rect.right, rect.bottom, 20, 20);
|
||||||
|
} else {
|
||||||
|
Rectangle(hdc, 0, 0, rect.right, rect.bottom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ActiveWindowBorderStyle::Rounded => {
|
||||||
|
RoundRect(hdc, 0, 0, rect.right, rect.bottom, 20, 20);
|
||||||
|
}
|
||||||
|
ActiveWindowBorderStyle::Square => {
|
||||||
|
Rectangle(hdc, 0, 0, rect.right, rect.bottom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EndPaint(window, &ps);
|
||||||
|
ValidateRect(window, None);
|
||||||
|
}
|
||||||
|
|
||||||
|
LRESULT(0)
|
||||||
|
}
|
||||||
|
WM_DESTROY => {
|
||||||
|
PostQuitMessage(0);
|
||||||
|
LRESULT(0)
|
||||||
|
}
|
||||||
|
_ => DefWindowProcW(window, message, wparam, lparam),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,288 @@
|
|||||||
|
mod border;
|
||||||
|
|
||||||
|
use crossbeam_channel::Receiver;
|
||||||
|
use crossbeam_channel::Sender;
|
||||||
|
use crossbeam_utils::atomic::AtomicConsume;
|
||||||
|
use komorebi_core::ActiveWindowBorderStyle;
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::Deserialize;
|
||||||
|
use serde::Serialize;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::sync::atomic::AtomicBool;
|
||||||
|
use std::sync::atomic::AtomicI32;
|
||||||
|
use std::sync::atomic::AtomicU32;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::OnceLock;
|
||||||
|
use windows::Win32::Foundation::HWND;
|
||||||
|
|
||||||
|
use crate::Colour;
|
||||||
|
use crate::Rect;
|
||||||
|
use crate::Rgb;
|
||||||
|
use crate::WindowManager;
|
||||||
|
use crate::WindowsApi;
|
||||||
|
use border::Border;
|
||||||
|
use komorebi_core::WindowKind;
|
||||||
|
|
||||||
|
pub static BORDER_WIDTH: AtomicI32 = AtomicI32::new(8);
|
||||||
|
pub static BORDER_OFFSET: AtomicI32 = AtomicI32::new(-1);
|
||||||
|
|
||||||
|
pub static BORDER_ENABLED: AtomicBool = AtomicBool::new(true);
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
pub static ref Z_ORDER: Arc<Mutex<ZOrder>> = Arc::new(Mutex::new(ZOrder::Bottom));
|
||||||
|
pub static ref STYLE: Arc<Mutex<ActiveWindowBorderStyle>> =
|
||||||
|
Arc::new(Mutex::new(ActiveWindowBorderStyle::System));
|
||||||
|
pub static ref FOCUSED: AtomicU32 =
|
||||||
|
AtomicU32::new(u32::from(Colour::Rgb(Rgb::new(66, 165, 245))));
|
||||||
|
pub static ref UNFOCUSED: AtomicU32 =
|
||||||
|
AtomicU32::new(u32::from(Colour::Rgb(Rgb::new(128, 128, 128))));
|
||||||
|
pub static ref MONOCLE: AtomicU32 =
|
||||||
|
AtomicU32::new(u32::from(Colour::Rgb(Rgb::new(255, 51, 153))));
|
||||||
|
pub static ref STACK: AtomicU32 = AtomicU32::new(u32::from(Colour::Rgb(Rgb::new(0, 165, 66))));
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
static ref BORDERS_MONITORS: Mutex<HashMap<String, usize>> = Mutex::new(HashMap::new());
|
||||||
|
static ref BORDER_STATE: Mutex<HashMap<String, Border>> = Mutex::new(HashMap::new());
|
||||||
|
static ref RECT_STATE: Mutex<HashMap<isize, Rect>> = Mutex::new(HashMap::new());
|
||||||
|
static ref FOCUS_STATE: Mutex<HashMap<isize, WindowKind>> = Mutex::new(HashMap::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Notification;
|
||||||
|
|
||||||
|
static CHANNEL: OnceLock<(Sender<Notification>, Receiver<Notification>)> = OnceLock::new();
|
||||||
|
|
||||||
|
pub fn channel() -> &'static (Sender<Notification>, Receiver<Notification>) {
|
||||||
|
CHANNEL.get_or_init(crossbeam_channel::unbounded)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn event_tx() -> Sender<Notification> {
|
||||||
|
channel().0.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn event_rx() -> Receiver<Notification> {
|
||||||
|
channel().1.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn listen_for_notifications(wm: Arc<Mutex<WindowManager>>) {
|
||||||
|
tracing::info!("listening");
|
||||||
|
let receiver = event_rx();
|
||||||
|
|
||||||
|
std::thread::spawn(move || -> color_eyre::Result<()> {
|
||||||
|
'receiver: for _ in receiver {
|
||||||
|
let mut borders = BORDER_STATE.lock();
|
||||||
|
let mut borders_monitors = BORDERS_MONITORS.lock();
|
||||||
|
|
||||||
|
// Check the wm state every time we receive a notification
|
||||||
|
let state = wm.lock();
|
||||||
|
|
||||||
|
if !BORDER_ENABLED.load_consume() || state.is_paused {
|
||||||
|
if !borders.is_empty() {
|
||||||
|
for (_, border) in borders.iter() {
|
||||||
|
border.destroy()?;
|
||||||
|
}
|
||||||
|
|
||||||
|
borders.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
continue 'receiver;
|
||||||
|
}
|
||||||
|
|
||||||
|
let focused_monitor_idx = state.focused_monitor_idx();
|
||||||
|
|
||||||
|
for (monitor_idx, m) in state.monitors.elements().iter().enumerate() {
|
||||||
|
// Only operate on the focused workspace of each monitor
|
||||||
|
if let Some(ws) = m.focused_workspace() {
|
||||||
|
// Workspaces with tiling disabled don't have borders
|
||||||
|
if !ws.tile() {
|
||||||
|
let mut to_remove = vec![];
|
||||||
|
for (id, border) in borders.iter() {
|
||||||
|
if borders_monitors.get(id).copied().unwrap_or_default() == monitor_idx
|
||||||
|
{
|
||||||
|
border.destroy()?;
|
||||||
|
to_remove.push(id.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for id in &to_remove {
|
||||||
|
borders.remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
continue 'receiver;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle the monocle container separately
|
||||||
|
if let Some(monocle) = ws.monocle_container() {
|
||||||
|
let mut to_remove = vec![];
|
||||||
|
for (id, border) in borders.iter() {
|
||||||
|
if borders_monitors.get(id).copied().unwrap_or_default() == monitor_idx
|
||||||
|
{
|
||||||
|
border.destroy()?;
|
||||||
|
to_remove.push(id.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for id in &to_remove {
|
||||||
|
borders.remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
let border = borders.entry(monocle.id().clone()).or_insert_with(|| {
|
||||||
|
Border::create(monocle.id()).expect("border creation failed")
|
||||||
|
});
|
||||||
|
|
||||||
|
borders_monitors.insert(monocle.id().clone(), monitor_idx);
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut focus_state = FOCUS_STATE.lock();
|
||||||
|
focus_state.insert(border.hwnd, WindowKind::Monocle);
|
||||||
|
}
|
||||||
|
|
||||||
|
let rect = WindowsApi::window_rect(
|
||||||
|
monocle
|
||||||
|
.focused_window()
|
||||||
|
.expect("monocle container has no focused window")
|
||||||
|
.hwnd(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
border.update(&rect)?;
|
||||||
|
continue 'receiver;
|
||||||
|
}
|
||||||
|
|
||||||
|
let is_maximized = WindowsApi::is_zoomed(HWND(
|
||||||
|
WindowsApi::foreground_window().unwrap_or_default(),
|
||||||
|
));
|
||||||
|
|
||||||
|
if is_maximized {
|
||||||
|
let mut to_remove = vec![];
|
||||||
|
for (id, border) in borders.iter() {
|
||||||
|
if borders_monitors.get(id).copied().unwrap_or_default() == monitor_idx
|
||||||
|
{
|
||||||
|
border.destroy()?;
|
||||||
|
to_remove.push(id.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for id in &to_remove {
|
||||||
|
borders.remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
continue 'receiver;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Destroy any borders not associated with the focused workspace
|
||||||
|
let container_ids = ws
|
||||||
|
.containers()
|
||||||
|
.iter()
|
||||||
|
.map(|c| c.id().clone())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let mut to_remove = vec![];
|
||||||
|
for (id, border) in borders.iter() {
|
||||||
|
if borders_monitors.get(id).copied().unwrap_or_default() == monitor_idx {
|
||||||
|
if !container_ids.contains(id) {
|
||||||
|
border.destroy()?;
|
||||||
|
to_remove.push(id.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for id in &to_remove {
|
||||||
|
borders.remove(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (idx, c) in ws.containers().iter().enumerate() {
|
||||||
|
// Update border when moving or resizing with mouse
|
||||||
|
if state.pending_move_op.is_some() && idx == ws.focused_container_idx() {
|
||||||
|
let restore_z_order = *Z_ORDER.lock();
|
||||||
|
*Z_ORDER.lock() = ZOrder::TopMost;
|
||||||
|
|
||||||
|
let mut rect = WindowsApi::window_rect(
|
||||||
|
c.focused_window()
|
||||||
|
.expect("container has no focused window")
|
||||||
|
.hwnd(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
while WindowsApi::lbutton_is_pressed() {
|
||||||
|
let border = borders.entry(c.id().clone()).or_insert_with(|| {
|
||||||
|
Border::create(c.id()).expect("border creation failed")
|
||||||
|
});
|
||||||
|
|
||||||
|
let new_rect = WindowsApi::window_rect(
|
||||||
|
c.focused_window()
|
||||||
|
.expect("container has no focused window")
|
||||||
|
.hwnd(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
if rect != new_rect {
|
||||||
|
rect = new_rect;
|
||||||
|
border.update(&rect)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*Z_ORDER.lock() = restore_z_order;
|
||||||
|
|
||||||
|
continue 'receiver;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the border entry for this container from the map or create one
|
||||||
|
let border = borders.entry(c.id().clone()).or_insert_with(|| {
|
||||||
|
Border::create(c.id()).expect("border creation failed")
|
||||||
|
});
|
||||||
|
|
||||||
|
borders_monitors.insert(c.id().clone(), monitor_idx);
|
||||||
|
|
||||||
|
// Update the focused state for all containers on this workspace
|
||||||
|
{
|
||||||
|
let mut focus_state = FOCUS_STATE.lock();
|
||||||
|
focus_state.insert(
|
||||||
|
border.hwnd,
|
||||||
|
if idx != ws.focused_container_idx()
|
||||||
|
|| monitor_idx != focused_monitor_idx
|
||||||
|
{
|
||||||
|
WindowKind::Unfocused
|
||||||
|
} else {
|
||||||
|
if c.windows().len() > 1 {
|
||||||
|
WindowKind::Stack
|
||||||
|
} else {
|
||||||
|
WindowKind::Single
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let rect = WindowsApi::window_rect(
|
||||||
|
c.focused_window()
|
||||||
|
.expect("container has no focused window")
|
||||||
|
.hwnd(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
border.update(&rect)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Copy, Clone, Serialize, Deserialize, JsonSchema)]
|
||||||
|
pub enum ZOrder {
|
||||||
|
Top,
|
||||||
|
NoTopMost,
|
||||||
|
Bottom,
|
||||||
|
TopMost,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<isize> for ZOrder {
|
||||||
|
fn into(self) -> isize {
|
||||||
|
match self {
|
||||||
|
ZOrder::Top => 0,
|
||||||
|
ZOrder::NoTopMost => -2,
|
||||||
|
ZOrder::Bottom => 1,
|
||||||
|
ZOrder::TopMost => -1,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -65,7 +65,7 @@ pub struct Rgb {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Rgb {
|
impl Rgb {
|
||||||
pub fn new(r: u32, g: u32, b: u32) -> Self {
|
pub const fn new(r: u32, g: u32, b: u32) -> Self {
|
||||||
Self { r, g, b }
|
Self { r, g, b }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ use windows::Win32::UI::WindowsAndMessaging::WNDCLASSW;
|
|||||||
use crate::windows_callbacks;
|
use crate::windows_callbacks;
|
||||||
use crate::WindowsApi;
|
use crate::WindowsApi;
|
||||||
use crate::HIDDEN_HWND;
|
use crate::HIDDEN_HWND;
|
||||||
use crate::TRANSPARENCY_COLOUR;
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Hidden {
|
pub struct Hidden {
|
||||||
@@ -36,7 +35,7 @@ impl Hidden {
|
|||||||
let name: Vec<u16> = format!("{name}\0").encode_utf16().collect();
|
let name: Vec<u16> = format!("{name}\0").encode_utf16().collect();
|
||||||
let instance = WindowsApi::module_handle_w()?;
|
let instance = WindowsApi::module_handle_w()?;
|
||||||
let class_name = PCWSTR(name.as_ptr());
|
let class_name = PCWSTR(name.as_ptr());
|
||||||
let brush = WindowsApi::create_solid_brush(TRANSPARENCY_COLOUR);
|
let brush = WindowsApi::create_solid_brush(0);
|
||||||
let window_class = WNDCLASSW {
|
let window_class = WNDCLASSW {
|
||||||
hInstance: instance.into(),
|
hInstance: instance.into(),
|
||||||
lpszClassName: class_name,
|
lpszClassName: class_name,
|
||||||
|
|||||||
+1
-20
@@ -1,4 +1,4 @@
|
|||||||
pub mod border;
|
pub mod border_manager;
|
||||||
pub mod com;
|
pub mod com;
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
pub mod ring;
|
pub mod ring;
|
||||||
@@ -53,7 +53,6 @@ use color_eyre::Result;
|
|||||||
use komorebi_core::config_generation::IdWithIdentifier;
|
use komorebi_core::config_generation::IdWithIdentifier;
|
||||||
use komorebi_core::config_generation::MatchingRule;
|
use komorebi_core::config_generation::MatchingRule;
|
||||||
use komorebi_core::config_generation::MatchingStrategy;
|
use komorebi_core::config_generation::MatchingStrategy;
|
||||||
use komorebi_core::ActiveWindowBorderStyle;
|
|
||||||
use komorebi_core::ApplicationIdentifier;
|
use komorebi_core::ApplicationIdentifier;
|
||||||
use komorebi_core::HidingBehaviour;
|
use komorebi_core::HidingBehaviour;
|
||||||
use komorebi_core::Rect;
|
use komorebi_core::Rect;
|
||||||
@@ -197,13 +196,6 @@ lazy_static! {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
static ref ACTIVE_WINDOW_BORDER_STYLE: Arc<Mutex<ActiveWindowBorderStyle>> =
|
|
||||||
Arc::new(Mutex::new(ActiveWindowBorderStyle::System));
|
|
||||||
|
|
||||||
static ref BORDER_RECT: Arc<Mutex<Rect>> =
|
|
||||||
Arc::new(Mutex::new(Rect::default()));
|
|
||||||
|
|
||||||
|
|
||||||
// Use app-specific titlebar removal options where possible
|
// Use app-specific titlebar removal options where possible
|
||||||
// eg. Windows Terminal, IntelliJ IDEA, Firefox
|
// eg. Windows Terminal, IntelliJ IDEA, Firefox
|
||||||
static ref NO_TITLEBAR: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![]));
|
static ref NO_TITLEBAR: Arc<Mutex<Vec<String>>> = Arc::new(Mutex::new(vec![]));
|
||||||
@@ -220,18 +212,7 @@ pub static DEFAULT_CONTAINER_PADDING: AtomicI32 = AtomicI32::new(10);
|
|||||||
pub static INITIAL_CONFIGURATION_LOADED: AtomicBool = AtomicBool::new(false);
|
pub static INITIAL_CONFIGURATION_LOADED: AtomicBool = AtomicBool::new(false);
|
||||||
pub static CUSTOM_FFM: AtomicBool = AtomicBool::new(false);
|
pub static CUSTOM_FFM: AtomicBool = AtomicBool::new(false);
|
||||||
pub static SESSION_ID: AtomicU32 = AtomicU32::new(0);
|
pub static SESSION_ID: AtomicU32 = AtomicU32::new(0);
|
||||||
pub static BORDER_ENABLED: AtomicBool = AtomicBool::new(false);
|
|
||||||
pub static BORDER_HWND: AtomicIsize = AtomicIsize::new(0);
|
|
||||||
pub static BORDER_HIDDEN: AtomicBool = AtomicBool::new(false);
|
|
||||||
pub static BORDER_COLOUR_SINGLE: AtomicU32 = AtomicU32::new(0);
|
|
||||||
pub static BORDER_COLOUR_STACK: AtomicU32 = AtomicU32::new(0);
|
|
||||||
pub static BORDER_COLOUR_MONOCLE: AtomicU32 = AtomicU32::new(0);
|
|
||||||
pub static BORDER_COLOUR_CURRENT: AtomicU32 = AtomicU32::new(0);
|
|
||||||
pub static BORDER_WIDTH: AtomicI32 = AtomicI32::new(8);
|
|
||||||
pub static BORDER_OFFSET: AtomicI32 = AtomicI32::new(-1);
|
|
||||||
|
|
||||||
// 0 0 0 aka pure black, I doubt anyone will want this as a border colour
|
|
||||||
pub const TRANSPARENCY_COLOUR: u32 = 0;
|
|
||||||
pub static REMOVE_TITLEBARS: AtomicBool = AtomicBool::new(false);
|
pub static REMOVE_TITLEBARS: AtomicBool = AtomicBool::new(false);
|
||||||
|
|
||||||
pub static HIDDEN_HWND: AtomicIsize = AtomicIsize::new(0);
|
pub static HIDDEN_HWND: AtomicIsize = AtomicIsize::new(0);
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ use tracing_appender::non_blocking::WorkerGuard;
|
|||||||
use tracing_subscriber::layer::SubscriberExt;
|
use tracing_subscriber::layer::SubscriberExt;
|
||||||
use tracing_subscriber::EnvFilter;
|
use tracing_subscriber::EnvFilter;
|
||||||
|
|
||||||
|
use komorebi::border_manager;
|
||||||
use komorebi::hidden::Hidden;
|
use komorebi::hidden::Hidden;
|
||||||
use komorebi::load_configuration;
|
use komorebi::load_configuration;
|
||||||
use komorebi::process_command::listen_for_commands;
|
use komorebi::process_command::listen_for_commands;
|
||||||
@@ -253,6 +254,8 @@ fn main() -> Result<()> {
|
|||||||
listen_for_movements(wm.clone());
|
listen_for_movements(wm.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
border_manager::listen_for_notifications(wm.clone());
|
||||||
|
|
||||||
let (ctrlc_sender, ctrlc_receiver) = crossbeam_channel::bounded(1);
|
let (ctrlc_sender, ctrlc_receiver) = crossbeam_channel::bounded(1);
|
||||||
ctrlc::set_handler(move || {
|
ctrlc::set_handler(move || {
|
||||||
ctrlc_sender
|
ctrlc_sender
|
||||||
|
|||||||
+25
-235
@@ -13,7 +13,6 @@ use std::sync::Arc;
|
|||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use color_eyre::eyre::anyhow;
|
use color_eyre::eyre::anyhow;
|
||||||
use color_eyre::eyre::bail;
|
|
||||||
use color_eyre::Result;
|
use color_eyre::Result;
|
||||||
use miow::pipe::connect;
|
use miow::pipe::connect;
|
||||||
use net2::TcpStreamExt;
|
use net2::TcpStreamExt;
|
||||||
@@ -39,7 +38,8 @@ use komorebi_core::StateQuery;
|
|||||||
use komorebi_core::WindowContainerBehaviour;
|
use komorebi_core::WindowContainerBehaviour;
|
||||||
use komorebi_core::WindowKind;
|
use komorebi_core::WindowKind;
|
||||||
|
|
||||||
use crate::border::Border;
|
use crate::border_manager;
|
||||||
|
use crate::border_manager::STYLE;
|
||||||
use crate::colour::Rgb;
|
use crate::colour::Rgb;
|
||||||
use crate::current_virtual_desktop;
|
use crate::current_virtual_desktop;
|
||||||
use crate::notify_subscribers;
|
use crate::notify_subscribers;
|
||||||
@@ -52,16 +52,6 @@ use crate::windows_api::WindowsApi;
|
|||||||
use crate::GlobalState;
|
use crate::GlobalState;
|
||||||
use crate::Notification;
|
use crate::Notification;
|
||||||
use crate::NotificationEvent;
|
use crate::NotificationEvent;
|
||||||
use crate::ACTIVE_WINDOW_BORDER_STYLE;
|
|
||||||
use crate::BORDER_COLOUR_CURRENT;
|
|
||||||
use crate::BORDER_COLOUR_MONOCLE;
|
|
||||||
use crate::BORDER_COLOUR_SINGLE;
|
|
||||||
use crate::BORDER_COLOUR_STACK;
|
|
||||||
use crate::BORDER_ENABLED;
|
|
||||||
use crate::BORDER_HIDDEN;
|
|
||||||
use crate::BORDER_HWND;
|
|
||||||
use crate::BORDER_OFFSET;
|
|
||||||
use crate::BORDER_WIDTH;
|
|
||||||
use crate::CUSTOM_FFM;
|
use crate::CUSTOM_FFM;
|
||||||
use crate::DATA_DIR;
|
use crate::DATA_DIR;
|
||||||
use crate::DISPLAY_INDEX_PREFERENCES;
|
use crate::DISPLAY_INDEX_PREFERENCES;
|
||||||
@@ -175,21 +165,6 @@ impl WindowManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match message {
|
|
||||||
SocketMessage::CycleFocusMonitor(_)
|
|
||||||
| SocketMessage::CycleFocusWorkspace(_)
|
|
||||||
| SocketMessage::FocusMonitorNumber(_)
|
|
||||||
| SocketMessage::FocusMonitorWorkspaceNumber(_, _)
|
|
||||||
| SocketMessage::FocusWorkspaceNumber(_) => {
|
|
||||||
if self.focused_workspace()?.visible_windows().is_empty() {
|
|
||||||
let border = Border::from(BORDER_HWND.load(Ordering::SeqCst));
|
|
||||||
border.hide()?;
|
|
||||||
BORDER_HIDDEN.store(true, Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
|
|
||||||
match message {
|
match message {
|
||||||
SocketMessage::CycleFocusWorkspace(_) | SocketMessage::FocusWorkspaceNumber(_) => {
|
SocketMessage::CycleFocusWorkspace(_) | SocketMessage::FocusWorkspaceNumber(_) => {
|
||||||
if let Some(monitor) = self.focused_monitor_mut() {
|
if let Some(monitor) = self.focused_monitor_mut() {
|
||||||
@@ -640,10 +615,6 @@ impl WindowManager {
|
|||||||
);
|
);
|
||||||
|
|
||||||
self.focus_workspace(workspace_idx)?;
|
self.focus_workspace(workspace_idx)?;
|
||||||
|
|
||||||
if BORDER_ENABLED.load(Ordering::SeqCst) {
|
|
||||||
self.show_border()?;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
SocketMessage::FocusLastWorkspace => {
|
SocketMessage::FocusLastWorkspace => {
|
||||||
// This is to ensure that even on an empty workspace on a secondary monitor, the
|
// This is to ensure that even on an empty workspace on a secondary monitor, the
|
||||||
@@ -667,10 +638,6 @@ impl WindowManager {
|
|||||||
self.focused_monitor_mut()
|
self.focused_monitor_mut()
|
||||||
.ok_or_else(|| anyhow!("there is no monitor"))?
|
.ok_or_else(|| anyhow!("there is no monitor"))?
|
||||||
.set_last_focused_workspace(Option::from(idx));
|
.set_last_focused_workspace(Option::from(idx));
|
||||||
|
|
||||||
if BORDER_ENABLED.load(Ordering::SeqCst) {
|
|
||||||
self.show_border()?;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
SocketMessage::FocusWorkspaceNumber(workspace_idx) => {
|
SocketMessage::FocusWorkspaceNumber(workspace_idx) => {
|
||||||
// This is to ensure that even on an empty workspace on a secondary monitor, the
|
// This is to ensure that even on an empty workspace on a secondary monitor, the
|
||||||
@@ -681,10 +648,6 @@ impl WindowManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.focus_workspace(workspace_idx)?;
|
self.focus_workspace(workspace_idx)?;
|
||||||
|
|
||||||
if BORDER_ENABLED.load(Ordering::SeqCst) {
|
|
||||||
self.show_border()?;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
SocketMessage::FocusWorkspaceNumbers(workspace_idx) => {
|
SocketMessage::FocusWorkspaceNumbers(workspace_idx) => {
|
||||||
// This is to ensure that even on an empty workspace on a secondary monitor, the
|
// This is to ensure that even on an empty workspace on a secondary monitor, the
|
||||||
@@ -704,10 +667,6 @@ impl WindowManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
self.focus_workspace(workspace_idx)?;
|
self.focus_workspace(workspace_idx)?;
|
||||||
|
|
||||||
if BORDER_ENABLED.load(Ordering::SeqCst) {
|
|
||||||
self.show_border()?;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
SocketMessage::FocusMonitorWorkspaceNumber(monitor_idx, workspace_idx) => {
|
SocketMessage::FocusMonitorWorkspaceNumber(monitor_idx, workspace_idx) => {
|
||||||
self.focus_monitor(monitor_idx)?;
|
self.focus_monitor(monitor_idx)?;
|
||||||
@@ -720,10 +679,6 @@ impl WindowManager {
|
|||||||
self.focus_monitor(monitor_idx)?;
|
self.focus_monitor(monitor_idx)?;
|
||||||
self.focus_workspace(workspace_idx)?;
|
self.focus_workspace(workspace_idx)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
if BORDER_ENABLED.load(Ordering::SeqCst) {
|
|
||||||
self.show_border()?;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
SocketMessage::Stop => {
|
SocketMessage::Stop => {
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
@@ -1238,47 +1193,31 @@ impl WindowManager {
|
|||||||
self.unmanaged_window_operation_behaviour = behaviour;
|
self.unmanaged_window_operation_behaviour = behaviour;
|
||||||
}
|
}
|
||||||
SocketMessage::ActiveWindowBorder(enable) => {
|
SocketMessage::ActiveWindowBorder(enable) => {
|
||||||
if enable {
|
border_manager::BORDER_ENABLED.store(enable, Ordering::SeqCst);
|
||||||
if BORDER_HWND.load(Ordering::SeqCst) == 0 {
|
|
||||||
Border::create("komorebi-border-window")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
BORDER_ENABLED.store(true, Ordering::SeqCst);
|
|
||||||
self.show_border()?;
|
|
||||||
} else {
|
|
||||||
BORDER_ENABLED.store(false, Ordering::SeqCst);
|
|
||||||
self.hide_border()?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
SocketMessage::ActiveWindowBorderColour(kind, r, g, b) => {
|
SocketMessage::ActiveWindowBorderColour(kind, r, g, b) => match kind {
|
||||||
match kind {
|
WindowKind::Single => {
|
||||||
WindowKind::Single => {
|
border_manager::FOCUSED.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
|
||||||
BORDER_COLOUR_SINGLE.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
|
|
||||||
BORDER_COLOUR_CURRENT.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
WindowKind::Stack => {
|
|
||||||
BORDER_COLOUR_STACK.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
WindowKind::Monocle => {
|
|
||||||
BORDER_COLOUR_MONOCLE.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
WindowKind::Stack => {
|
||||||
WindowsApi::invalidate_border_rect()?;
|
border_manager::STACK.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
WindowKind::Monocle => {
|
||||||
|
border_manager::MONOCLE.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
WindowKind::Unfocused => {
|
||||||
|
border_manager::UNFOCUSED.store(Rgb::new(r, g, b).into(), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
},
|
||||||
SocketMessage::ActiveWindowBorderStyle(style) => {
|
SocketMessage::ActiveWindowBorderStyle(style) => {
|
||||||
let mut active_window_border_style = ACTIVE_WINDOW_BORDER_STYLE.lock();
|
let mut active_window_border_style = STYLE.lock();
|
||||||
*active_window_border_style = style;
|
*active_window_border_style = style;
|
||||||
|
|
||||||
WindowsApi::invalidate_border_rect()?;
|
|
||||||
}
|
}
|
||||||
SocketMessage::BorderWidth(width) => {
|
SocketMessage::BorderWidth(width) => {
|
||||||
BORDER_WIDTH.store(width, Ordering::SeqCst);
|
border_manager::BORDER_WIDTH.store(width, Ordering::SeqCst);
|
||||||
WindowsApi::invalidate_border_rect()?;
|
|
||||||
}
|
}
|
||||||
SocketMessage::BorderOffset(offset) => {
|
SocketMessage::BorderOffset(offset) => {
|
||||||
BORDER_OFFSET.store(offset, Ordering::SeqCst);
|
border_manager::BORDER_OFFSET.store(offset, Ordering::SeqCst);
|
||||||
WindowsApi::invalidate_border_rect()?;
|
|
||||||
}
|
}
|
||||||
SocketMessage::StackbarMode(mode) => {
|
SocketMessage::StackbarMode(mode) => {
|
||||||
let mut stackbar_mode = STACKBAR_MODE.lock();
|
let mut stackbar_mode = STACKBAR_MODE.lock();
|
||||||
@@ -1370,155 +1309,14 @@ impl WindowManager {
|
|||||||
| SocketMessage::IdentifyBorderOverflowApplication(_, _) => {}
|
| SocketMessage::IdentifyBorderOverflowApplication(_, _) => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
match message {
|
let notification = Notification {
|
||||||
SocketMessage::ToggleMonocle => {
|
event: NotificationEvent::Socket(message.clone()),
|
||||||
let current = BORDER_COLOUR_CURRENT.load(Ordering::SeqCst);
|
state: self.as_ref().into(),
|
||||||
let monocle = BORDER_COLOUR_MONOCLE.load(Ordering::SeqCst);
|
|
||||||
|
|
||||||
if monocle != 0 {
|
|
||||||
if current == monocle {
|
|
||||||
BORDER_COLOUR_CURRENT.store(
|
|
||||||
BORDER_COLOUR_SINGLE.load(Ordering::SeqCst),
|
|
||||||
Ordering::SeqCst,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
BORDER_COLOUR_CURRENT.store(
|
|
||||||
BORDER_COLOUR_MONOCLE.load(Ordering::SeqCst),
|
|
||||||
Ordering::SeqCst,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SocketMessage::StackWindow(_) => {
|
|
||||||
let stack = BORDER_COLOUR_STACK.load(Ordering::SeqCst);
|
|
||||||
if stack != 0 {
|
|
||||||
BORDER_COLOUR_CURRENT
|
|
||||||
.store(BORDER_COLOUR_STACK.load(Ordering::SeqCst), Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SocketMessage::UnstackWindow => {
|
|
||||||
BORDER_COLOUR_CURRENT.store(
|
|
||||||
BORDER_COLOUR_SINGLE.load(Ordering::SeqCst),
|
|
||||||
Ordering::SeqCst,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
|
|
||||||
match message {
|
|
||||||
SocketMessage::ChangeLayout(_)
|
|
||||||
| SocketMessage::CycleLayout(_)
|
|
||||||
| SocketMessage::ChangeLayoutCustom(_)
|
|
||||||
| SocketMessage::FlipLayout(_)
|
|
||||||
| SocketMessage::ManageFocusedWindow
|
|
||||||
| SocketMessage::MoveWorkspaceToMonitorNumber(_)
|
|
||||||
| SocketMessage::MoveContainerToMonitorNumber(_)
|
|
||||||
| SocketMessage::MoveContainerToWorkspaceNumber(_)
|
|
||||||
| SocketMessage::MoveContainerToMonitorWorkspaceNumber(_, _)
|
|
||||||
| SocketMessage::MoveContainerToNamedWorkspace(_)
|
|
||||||
| SocketMessage::ResizeWindowEdge(_, _)
|
|
||||||
| SocketMessage::ResizeWindowAxis(_, _)
|
|
||||||
| SocketMessage::ToggleFloat
|
|
||||||
| SocketMessage::ToggleMonocle
|
|
||||||
| SocketMessage::ToggleMaximize
|
|
||||||
| SocketMessage::Promote
|
|
||||||
| SocketMessage::PromoteFocus
|
|
||||||
| SocketMessage::StackWindow(_)
|
|
||||||
| SocketMessage::UnstackWindow
|
|
||||||
| SocketMessage::Retile
|
|
||||||
// Adding this one so that changes can be seen instantly after
|
|
||||||
// modifying the active window border offset
|
|
||||||
| SocketMessage::BorderOffset(_)
|
|
||||||
// Adding this one because sometimes EVENT_SYSTEM_FOREGROUND isn't
|
|
||||||
// getting sent on FocusWindow, meaning the border won't be set
|
|
||||||
// when processing events
|
|
||||||
| SocketMessage::FocusWindow(_)
|
|
||||||
| SocketMessage::InvisibleBorders(_)
|
|
||||||
| SocketMessage::WorkAreaOffset(_)
|
|
||||||
| SocketMessage::CycleMoveWindow(_)
|
|
||||||
| SocketMessage::MoveWindow(_)
|
|
||||||
| SocketMessage::CycleFocusMonitor(_)
|
|
||||||
| SocketMessage::CycleFocusWorkspace(_)
|
|
||||||
| SocketMessage::FocusMonitorNumber(_)
|
|
||||||
| SocketMessage::FocusMonitorWorkspaceNumber(_, _)
|
|
||||||
| SocketMessage::FocusWorkspaceNumber(_) => {
|
|
||||||
// The foreground window might be de-activating if we've just
|
|
||||||
// set it as a result of our own actions, so wait until the new
|
|
||||||
// one returns. This particularly happens when switching monitors.
|
|
||||||
//
|
|
||||||
// TODO(raggi): re-evaluate this branch. I checked the
|
|
||||||
// suggestion from the comment above, that we don't get
|
|
||||||
// EVENT_SYSTEM_FOREGROUND, but if I print out trace events I
|
|
||||||
// see that we do.
|
|
||||||
// XXX(raggi) We drop FocusChange events though for windows that
|
|
||||||
// we're not managing, so that's one of the ways that the border
|
|
||||||
// window gets stuck. We should stop overloading `should_manage`
|
|
||||||
// as an event filter, and separately filter events that we want
|
|
||||||
// to handle, and windows that we want to handle, as some events
|
|
||||||
// must be handled even if we're not managing the target window.
|
|
||||||
let mut attempts = 0;
|
|
||||||
let foreground = loop {
|
|
||||||
match WindowsApi::foreground_window() {
|
|
||||||
Ok(foreground) => break foreground,
|
|
||||||
Err(_) => {
|
|
||||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
|
||||||
attempts+=1;
|
|
||||||
if attempts == 10 {
|
|
||||||
bail!("failed to get foreground window after 100ms")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
let foreground_window = Window { hwnd: foreground };
|
|
||||||
|
|
||||||
let monocle = BORDER_COLOUR_MONOCLE.load(Ordering::SeqCst);
|
|
||||||
if monocle != 0 && self.focused_workspace()?.monocle_container().is_some() {
|
|
||||||
BORDER_COLOUR_CURRENT.store(
|
|
||||||
monocle,
|
|
||||||
Ordering::SeqCst,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// it is not acceptable to fail here; we need to be able to send the event to
|
|
||||||
// subscribers
|
|
||||||
if self.focused_container().is_ok() {
|
|
||||||
let stack = BORDER_COLOUR_STACK.load(Ordering::SeqCst);
|
|
||||||
if stack != 0 && self.focused_container()?.windows().len() > 1 {
|
|
||||||
BORDER_COLOUR_CURRENT
|
|
||||||
.store(stack, Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let border = Border::from(BORDER_HWND.load(Ordering::SeqCst));
|
|
||||||
border.set_position(foreground_window, false)?;
|
|
||||||
}
|
|
||||||
SocketMessage::TogglePause => {
|
|
||||||
let is_paused = self.is_paused;
|
|
||||||
let border = Border::from(BORDER_HWND.load(Ordering::SeqCst));
|
|
||||||
|
|
||||||
if is_paused {
|
|
||||||
border.hide()?;
|
|
||||||
} else {
|
|
||||||
let focused = self.focused_window()?;
|
|
||||||
border.set_position(*focused, true)?;
|
|
||||||
focused.focus(false)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SocketMessage::ToggleTiling | SocketMessage::WorkspaceTiling(..) => {
|
|
||||||
let tiling_enabled = *self.focused_workspace_mut()?.tile();
|
|
||||||
let border = Border::from(BORDER_HWND.load(Ordering::SeqCst));
|
|
||||||
|
|
||||||
if tiling_enabled {
|
|
||||||
let focused = self.focused_window()?;
|
|
||||||
border.set_position(*focused, true)?;
|
|
||||||
focused.focus(false)?;
|
|
||||||
} else {
|
|
||||||
border.hide()?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
notify_subscribers(&serde_json::to_string(¬ification)?)?;
|
||||||
|
border_manager::event_tx().send(border_manager::Notification)?;
|
||||||
|
|
||||||
tracing::info!("processed");
|
tracing::info!("processed");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -1594,10 +1392,6 @@ pub fn read_commands_uds(wm: &Arc<Mutex<WindowManager>>, mut stream: UnixStream)
|
|||||||
}
|
}
|
||||||
|
|
||||||
wm.process_command(message.clone(), &mut stream)?;
|
wm.process_command(message.clone(), &mut stream)?;
|
||||||
notify_subscribers(&serde_json::to_string(&Notification {
|
|
||||||
event: NotificationEvent::Socket(message.clone()),
|
|
||||||
state: wm.as_ref().into(),
|
|
||||||
})?)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -1644,10 +1438,6 @@ pub fn read_commands_tcp(
|
|||||||
}
|
}
|
||||||
|
|
||||||
wm.process_command(message.clone(), &mut *stream)?;
|
wm.process_command(message.clone(), &mut *stream)?;
|
||||||
notify_subscribers(&serde_json::to_string(&Notification {
|
|
||||||
event: NotificationEvent::Socket(message.clone()),
|
|
||||||
state: wm.as_ref().into(),
|
|
||||||
})?)?;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-129
@@ -11,7 +11,9 @@ use komorebi_core::Rect;
|
|||||||
use komorebi_core::Sizing;
|
use komorebi_core::Sizing;
|
||||||
use komorebi_core::WindowContainerBehaviour;
|
use komorebi_core::WindowContainerBehaviour;
|
||||||
|
|
||||||
use crate::border::Border;
|
use crate::border_manager;
|
||||||
|
use crate::border_manager::BORDER_OFFSET;
|
||||||
|
use crate::border_manager::BORDER_WIDTH;
|
||||||
use crate::current_virtual_desktop;
|
use crate::current_virtual_desktop;
|
||||||
use crate::notify_subscribers;
|
use crate::notify_subscribers;
|
||||||
use crate::window::should_act;
|
use crate::window::should_act;
|
||||||
@@ -19,17 +21,9 @@ use crate::window::RuleDebug;
|
|||||||
use crate::window_manager::WindowManager;
|
use crate::window_manager::WindowManager;
|
||||||
use crate::window_manager_event::WindowManagerEvent;
|
use crate::window_manager_event::WindowManagerEvent;
|
||||||
use crate::windows_api::WindowsApi;
|
use crate::windows_api::WindowsApi;
|
||||||
|
use crate::winevent::WinEvent;
|
||||||
use crate::Notification;
|
use crate::Notification;
|
||||||
use crate::NotificationEvent;
|
use crate::NotificationEvent;
|
||||||
use crate::BORDER_COLOUR_CURRENT;
|
|
||||||
use crate::BORDER_COLOUR_MONOCLE;
|
|
||||||
use crate::BORDER_COLOUR_SINGLE;
|
|
||||||
use crate::BORDER_COLOUR_STACK;
|
|
||||||
use crate::BORDER_ENABLED;
|
|
||||||
use crate::BORDER_HIDDEN;
|
|
||||||
use crate::BORDER_HWND;
|
|
||||||
use crate::BORDER_OFFSET;
|
|
||||||
use crate::BORDER_WIDTH;
|
|
||||||
use crate::DATA_DIR;
|
use crate::DATA_DIR;
|
||||||
use crate::HIDDEN_HWNDS;
|
use crate::HIDDEN_HWNDS;
|
||||||
use crate::REGEX_IDENTIFIERS;
|
use crate::REGEX_IDENTIFIERS;
|
||||||
@@ -71,28 +65,6 @@ impl WindowManager {
|
|||||||
|
|
||||||
let should_manage = event.window().should_manage(Some(event), &mut rule_debug)?;
|
let should_manage = event.window().should_manage(Some(event), &mut rule_debug)?;
|
||||||
|
|
||||||
// Hide or reposition the window based on whether the target is managed.
|
|
||||||
if BORDER_ENABLED.load(Ordering::SeqCst) {
|
|
||||||
if let WindowManagerEvent::FocusChange(_, window) = event {
|
|
||||||
let border_window = Border::from(BORDER_HWND.load(Ordering::SeqCst));
|
|
||||||
|
|
||||||
if should_manage {
|
|
||||||
border_window.set_position(window, true)?;
|
|
||||||
} else {
|
|
||||||
let mut stackbar = false;
|
|
||||||
if let Ok(class) = window.class() {
|
|
||||||
if class == "komorebi_stackbar" {
|
|
||||||
stackbar = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !stackbar {
|
|
||||||
border_window.hide()?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// All event handlers below this point should only be processed if the event is
|
// All event handlers below this point should only be processed if the event is
|
||||||
// related to a window that should be managed by the WindowManager.
|
// related to a window that should be managed by the WindowManager.
|
||||||
if !should_manage && !matches!(event, WindowManagerEvent::DisplayChange(_)) {
|
if !should_manage && !matches!(event, WindowManagerEvent::DisplayChange(_)) {
|
||||||
@@ -598,106 +570,11 @@ impl WindowManager {
|
|||||||
| WindowManagerEvent::Cloak(..) => {}
|
| WindowManagerEvent::Cloak(..) => {}
|
||||||
};
|
};
|
||||||
|
|
||||||
if !self.focused_workspace()?.tile() {
|
|
||||||
let border = Border::from(BORDER_HWND.load(Ordering::SeqCst));
|
|
||||||
border.hide()?;
|
|
||||||
BORDER_HIDDEN.store(true, Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
|
|
||||||
if *self.focused_workspace()?.tile() && BORDER_ENABLED.load(Ordering::SeqCst) {
|
|
||||||
match event {
|
|
||||||
WindowManagerEvent::MoveResizeStart(_, _) => {
|
|
||||||
let border = Border::from(BORDER_HWND.load(Ordering::SeqCst));
|
|
||||||
border.hide()?;
|
|
||||||
BORDER_HIDDEN.store(true, Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
WindowManagerEvent::MoveResizeEnd(_, window)
|
|
||||||
| WindowManagerEvent::Show(_, window)
|
|
||||||
| WindowManagerEvent::FocusChange(_, window)
|
|
||||||
| WindowManagerEvent::Hide(_, window)
|
|
||||||
| WindowManagerEvent::Uncloak(_, window)
|
|
||||||
| WindowManagerEvent::Minimize(_, window) => {
|
|
||||||
let border = Border::from(BORDER_HWND.load(Ordering::SeqCst));
|
|
||||||
let mut target_window = None;
|
|
||||||
let mut target_window_is_monocle = false;
|
|
||||||
if self
|
|
||||||
.focused_workspace()?
|
|
||||||
.floating_windows()
|
|
||||||
.iter()
|
|
||||||
.any(|w| w.hwnd == window.hwnd)
|
|
||||||
{
|
|
||||||
target_window = Option::from(window);
|
|
||||||
WindowsApi::raise_window(border.hwnd())?;
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(monocle_container) = self.focused_workspace()?.monocle_container() {
|
|
||||||
if let Some(window) = monocle_container.focused_window() {
|
|
||||||
target_window = Option::from(*window);
|
|
||||||
target_window_is_monocle = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if target_window.is_none() {
|
|
||||||
match self.focused_container() {
|
|
||||||
// if there is no focused container, the desktop is empty
|
|
||||||
Err(..) => {
|
|
||||||
WindowsApi::hide_border_window(border.hwnd())?;
|
|
||||||
}
|
|
||||||
Ok(container) => {
|
|
||||||
if !(matches!(event, WindowManagerEvent::Minimize(_, _))
|
|
||||||
&& container.windows().len() == 1)
|
|
||||||
{
|
|
||||||
let container_size = self.focused_container()?.windows().len();
|
|
||||||
target_window = Option::from(*self.focused_window()?);
|
|
||||||
|
|
||||||
if target_window_is_monocle {
|
|
||||||
BORDER_COLOUR_CURRENT.store(
|
|
||||||
BORDER_COLOUR_MONOCLE.load(Ordering::SeqCst),
|
|
||||||
Ordering::SeqCst,
|
|
||||||
);
|
|
||||||
} else if container_size > 1 {
|
|
||||||
BORDER_COLOUR_CURRENT.store(
|
|
||||||
BORDER_COLOUR_STACK.load(Ordering::SeqCst),
|
|
||||||
Ordering::SeqCst,
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
BORDER_COLOUR_CURRENT.store(
|
|
||||||
BORDER_COLOUR_SINGLE.load(Ordering::SeqCst),
|
|
||||||
Ordering::SeqCst,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(target_window) = target_window {
|
|
||||||
let activate = BORDER_HIDDEN.load(Ordering::SeqCst);
|
|
||||||
|
|
||||||
WindowsApi::invalidate_border_rect()?;
|
|
||||||
border.set_position(target_window, activate)?;
|
|
||||||
|
|
||||||
if activate {
|
|
||||||
BORDER_HIDDEN.store(false, Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If we unmanaged a window, it shouldn't be immediately hidden behind managed windows
|
// If we unmanaged a window, it shouldn't be immediately hidden behind managed windows
|
||||||
if let WindowManagerEvent::Unmanage(window) = event {
|
if let WindowManagerEvent::Unmanage(window) = event {
|
||||||
window.center(&self.focused_monitor_work_area()?)?;
|
window.center(&self.focused_monitor_work_area()?)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there are no more windows on the workspace, we shouldn't show the border window
|
|
||||||
if self.focused_workspace()?.containers().is_empty() {
|
|
||||||
let border = Border::from(BORDER_HWND.load(Ordering::SeqCst));
|
|
||||||
border.hide()?;
|
|
||||||
BORDER_HIDDEN.store(true, Ordering::SeqCst);
|
|
||||||
}
|
|
||||||
|
|
||||||
tracing::trace!("updating list of known hwnds");
|
tracing::trace!("updating list of known hwnds");
|
||||||
let mut known_hwnds = vec![];
|
let mut known_hwnds = vec![];
|
||||||
for monitor in self.monitors() {
|
for monitor in self.monitors() {
|
||||||
@@ -718,10 +595,21 @@ impl WindowManager {
|
|||||||
.open(hwnd_json)?;
|
.open(hwnd_json)?;
|
||||||
|
|
||||||
serde_json::to_writer_pretty(&file, &known_hwnds)?;
|
serde_json::to_writer_pretty(&file, &known_hwnds)?;
|
||||||
notify_subscribers(&serde_json::to_string(&Notification {
|
|
||||||
|
let notification = Notification {
|
||||||
event: NotificationEvent::WindowManager(event),
|
event: NotificationEvent::WindowManager(event),
|
||||||
state: self.as_ref().into(),
|
state: self.as_ref().into(),
|
||||||
})?)?;
|
};
|
||||||
|
|
||||||
|
// Avoid unnecessary updates, this fires every single time you interact
|
||||||
|
// with something on JetBrains IDEs
|
||||||
|
if !matches!(
|
||||||
|
event,
|
||||||
|
WindowManagerEvent::Show(WinEvent::ObjectNameChange, _)
|
||||||
|
) {
|
||||||
|
notify_subscribers(&serde_json::to_string(¬ification)?)?;
|
||||||
|
border_manager::event_tx().send(border_manager::Notification)?;
|
||||||
|
}
|
||||||
|
|
||||||
tracing::info!("processed: {}", event.window().to_string());
|
tracing::info!("processed: {}", event.window().to_string());
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -61,7 +61,6 @@ use crate::STACKBAR_TAB_BACKGROUND_COLOUR;
|
|||||||
use crate::STACKBAR_TAB_HEIGHT;
|
use crate::STACKBAR_TAB_HEIGHT;
|
||||||
use crate::STACKBAR_TAB_WIDTH;
|
use crate::STACKBAR_TAB_WIDTH;
|
||||||
use crate::STACKBAR_UNFOCUSED_TEXT_COLOUR;
|
use crate::STACKBAR_UNFOCUSED_TEXT_COLOUR;
|
||||||
use crate::TRANSPARENCY_COLOUR;
|
|
||||||
use crate::WINDOWS_BY_BAR_HWNDS;
|
use crate::WINDOWS_BY_BAR_HWNDS;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize, JsonSchema)]
|
||||||
@@ -129,7 +128,7 @@ impl Stackbar {
|
|||||||
lpfnWndProc: Some(Self::window_proc),
|
lpfnWndProc: Some(Self::window_proc),
|
||||||
hInstance: h_module.into(),
|
hInstance: h_module.into(),
|
||||||
lpszClassName: class_name,
|
lpszClassName: class_name,
|
||||||
hbrBackground: WindowsApi::create_solid_brush(TRANSPARENCY_COLOUR),
|
hbrBackground: WindowsApi::create_solid_brush(0),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -157,7 +156,7 @@ impl Stackbar {
|
|||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
SetLayeredWindowAttributes(hwnd, COLORREF(TRANSPARENCY_COLOUR), 0, LWA_COLORKEY)?;
|
SetLayeredWindowAttributes(hwnd, COLORREF(0), 0, LWA_COLORKEY)?;
|
||||||
hwnd_sender.send(hwnd)?;
|
hwnd_sender.send(hwnd)?;
|
||||||
|
|
||||||
let mut msg = MSG::default();
|
let mut msg = MSG::default();
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
use crate::border::Border;
|
use crate::border_manager;
|
||||||
|
use crate::border_manager::ZOrder;
|
||||||
|
use crate::border_manager::STYLE;
|
||||||
|
use crate::border_manager::Z_ORDER;
|
||||||
use crate::colour::Colour;
|
use crate::colour::Colour;
|
||||||
use crate::current_virtual_desktop;
|
use crate::current_virtual_desktop;
|
||||||
use crate::monitor::Monitor;
|
use crate::monitor::Monitor;
|
||||||
@@ -7,15 +10,6 @@ use crate::window_manager::WindowManager;
|
|||||||
use crate::window_manager_event::WindowManagerEvent;
|
use crate::window_manager_event::WindowManagerEvent;
|
||||||
use crate::windows_api::WindowsApi;
|
use crate::windows_api::WindowsApi;
|
||||||
use crate::workspace::Workspace;
|
use crate::workspace::Workspace;
|
||||||
use crate::ACTIVE_WINDOW_BORDER_STYLE;
|
|
||||||
use crate::BORDER_COLOUR_CURRENT;
|
|
||||||
use crate::BORDER_COLOUR_MONOCLE;
|
|
||||||
use crate::BORDER_COLOUR_SINGLE;
|
|
||||||
use crate::BORDER_COLOUR_STACK;
|
|
||||||
use crate::BORDER_ENABLED;
|
|
||||||
use crate::BORDER_HWND;
|
|
||||||
use crate::BORDER_OFFSET;
|
|
||||||
use crate::BORDER_WIDTH;
|
|
||||||
use crate::DATA_DIR;
|
use crate::DATA_DIR;
|
||||||
use crate::DEFAULT_CONTAINER_PADDING;
|
use crate::DEFAULT_CONTAINER_PADDING;
|
||||||
use crate::DEFAULT_WORKSPACE_PADDING;
|
use crate::DEFAULT_WORKSPACE_PADDING;
|
||||||
@@ -77,11 +71,13 @@ use uds_windows::UnixStream;
|
|||||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct ActiveWindowBorderColours {
|
pub struct ActiveWindowBorderColours {
|
||||||
/// Border colour when the container contains a single window
|
/// Border colour when the container contains a single window
|
||||||
pub single: Colour,
|
pub single: Option<Colour>,
|
||||||
/// Border colour when the container contains multiple windows
|
/// Border colour when the container contains multiple windows
|
||||||
pub stack: Colour,
|
pub stack: Option<Colour>,
|
||||||
/// Border colour when the container is in monocle mode
|
/// Border colour when the container is in monocle mode
|
||||||
pub monocle: Colour,
|
pub monocle: Option<Colour>,
|
||||||
|
/// Border colour when the container is unfocused
|
||||||
|
pub unfocused: Option<Colour>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
#[derive(Debug, Serialize, Deserialize, JsonSchema)]
|
||||||
@@ -265,6 +261,9 @@ pub struct StaticConfig {
|
|||||||
/// Active window border style (default: System)
|
/// Active window border style (default: System)
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub active_window_border_style: Option<ActiveWindowBorderStyle>,
|
pub active_window_border_style: Option<ActiveWindowBorderStyle>,
|
||||||
|
/// Active window border z-order (default: System)
|
||||||
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
|
pub active_window_border_z_order: Option<ZOrder>,
|
||||||
/// Global default workspace padding (default: 10)
|
/// Global default workspace padding (default: 10)
|
||||||
#[serde(skip_serializing_if = "Option::is_none")]
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
pub default_workspace_padding: Option<i32>,
|
pub default_workspace_padding: Option<i32>,
|
||||||
@@ -384,21 +383,16 @@ impl From<&WindowManager> for StaticConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let border_colours = if BORDER_COLOUR_SINGLE.load(Ordering::SeqCst) == 0 {
|
let border_colours = if border_manager::FOCUSED.load(Ordering::SeqCst) == 0 {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
Option::from(ActiveWindowBorderColours {
|
Option::from(ActiveWindowBorderColours {
|
||||||
single: Colour::from(BORDER_COLOUR_SINGLE.load(Ordering::SeqCst)),
|
single: Option::from(Colour::from(border_manager::FOCUSED.load(Ordering::SeqCst))),
|
||||||
stack: Colour::from(if BORDER_COLOUR_STACK.load(Ordering::SeqCst) == 0 {
|
stack: Option::from(Colour::from(border_manager::STACK.load(Ordering::SeqCst))),
|
||||||
BORDER_COLOUR_SINGLE.load(Ordering::SeqCst)
|
monocle: Option::from(Colour::from(border_manager::MONOCLE.load(Ordering::SeqCst))),
|
||||||
} else {
|
unfocused: Option::from(Colour::from(
|
||||||
BORDER_COLOUR_STACK.load(Ordering::SeqCst)
|
border_manager::UNFOCUSED.load(Ordering::SeqCst),
|
||||||
}),
|
)),
|
||||||
monocle: Colour::from(if BORDER_COLOUR_MONOCLE.load(Ordering::SeqCst) == 0 {
|
|
||||||
BORDER_COLOUR_SINGLE.load(Ordering::SeqCst)
|
|
||||||
} else {
|
|
||||||
BORDER_COLOUR_MONOCLE.load(Ordering::SeqCst)
|
|
||||||
}),
|
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -413,11 +407,14 @@ impl From<&WindowManager> for StaticConfig {
|
|||||||
focus_follows_mouse: value.focus_follows_mouse,
|
focus_follows_mouse: value.focus_follows_mouse,
|
||||||
mouse_follows_focus: Option::from(value.mouse_follows_focus),
|
mouse_follows_focus: Option::from(value.mouse_follows_focus),
|
||||||
app_specific_configuration_path: None,
|
app_specific_configuration_path: None,
|
||||||
border_width: Option::from(BORDER_WIDTH.load(Ordering::SeqCst)),
|
border_width: Option::from(border_manager::BORDER_WIDTH.load(Ordering::SeqCst)),
|
||||||
border_offset: Option::from(BORDER_OFFSET.load(Ordering::SeqCst)),
|
border_offset: Option::from(border_manager::BORDER_OFFSET.load(Ordering::SeqCst)),
|
||||||
active_window_border: Option::from(BORDER_ENABLED.load(Ordering::SeqCst)),
|
active_window_border: Option::from(
|
||||||
|
border_manager::BORDER_ENABLED.load(Ordering::SeqCst),
|
||||||
|
),
|
||||||
active_window_border_colours: border_colours,
|
active_window_border_colours: border_colours,
|
||||||
active_window_border_style: Option::from(*ACTIVE_WINDOW_BORDER_STYLE.lock()),
|
active_window_border_style: Option::from(*STYLE.lock()),
|
||||||
|
active_window_border_z_order: Option::from(*Z_ORDER.lock()),
|
||||||
default_workspace_padding: Option::from(
|
default_workspace_padding: Option::from(
|
||||||
DEFAULT_WORKSPACE_PADDING.load(Ordering::SeqCst),
|
DEFAULT_WORKSPACE_PADDING.load(Ordering::SeqCst),
|
||||||
),
|
),
|
||||||
@@ -466,26 +463,33 @@ impl StaticConfig {
|
|||||||
DEFAULT_WORKSPACE_PADDING.store(workspace, Ordering::SeqCst);
|
DEFAULT_WORKSPACE_PADDING.store(workspace, Ordering::SeqCst);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.border_width.map_or_else(
|
border_manager::BORDER_WIDTH.store(self.border_width.unwrap_or(8), Ordering::SeqCst);
|
||||||
|| {
|
border_manager::BORDER_OFFSET.store(self.border_offset.unwrap_or(-1), Ordering::SeqCst);
|
||||||
BORDER_WIDTH.store(8, Ordering::SeqCst);
|
|
||||||
},
|
|
||||||
|width| {
|
|
||||||
BORDER_WIDTH.store(width, Ordering::SeqCst);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
BORDER_OFFSET.store(self.border_offset.unwrap_or(-1), Ordering::SeqCst);
|
if let Some(enabled) = &self.active_window_border {
|
||||||
|
border_manager::BORDER_ENABLED.store(*enabled, Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(colours) = &self.active_window_border_colours {
|
if let Some(colours) = &self.active_window_border_colours {
|
||||||
BORDER_COLOUR_SINGLE.store(u32::from(colours.single), Ordering::SeqCst);
|
if let Some(single) = colours.single {
|
||||||
BORDER_COLOUR_CURRENT.store(u32::from(colours.single), Ordering::SeqCst);
|
border_manager::FOCUSED.store(u32::from(single), Ordering::SeqCst);
|
||||||
BORDER_COLOUR_STACK.store(u32::from(colours.stack), Ordering::SeqCst);
|
}
|
||||||
BORDER_COLOUR_MONOCLE.store(u32::from(colours.monocle), Ordering::SeqCst);
|
|
||||||
|
if let Some(stack) = colours.stack {
|
||||||
|
border_manager::STACK.store(u32::from(stack), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(monocle) = colours.monocle {
|
||||||
|
border_manager::MONOCLE.store(u32::from(monocle), Ordering::SeqCst);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(unfocused) = colours.unfocused {
|
||||||
|
border_manager::UNFOCUSED.store(u32::from(unfocused), Ordering::SeqCst);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let active_window_border_style = self.active_window_border_style.unwrap_or_default();
|
let active_window_border_style = self.active_window_border_style.unwrap_or_default();
|
||||||
*ACTIVE_WINDOW_BORDER_STYLE.lock() = active_window_border_style;
|
*STYLE.lock() = active_window_border_style;
|
||||||
|
|
||||||
let mut float_identifiers = FLOAT_IDENTIFIERS.lock();
|
let mut float_identifiers = FLOAT_IDENTIFIERS.lock();
|
||||||
let mut regex_identifiers = REGEX_IDENTIFIERS.lock();
|
let mut regex_identifiers = REGEX_IDENTIFIERS.lock();
|
||||||
@@ -718,12 +722,7 @@ impl StaticConfig {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if value.active_window_border == Some(true) {
|
if value.active_window_border == Some(true) {
|
||||||
if BORDER_HWND.load(Ordering::SeqCst) == 0 {
|
border_manager::BORDER_ENABLED.store(true, Ordering::SeqCst);
|
||||||
Border::create("komorebi-border-window")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
BORDER_ENABLED.store(true, Ordering::SeqCst);
|
|
||||||
wm.show_border()?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -777,16 +776,8 @@ impl StaticConfig {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if value.active_window_border == Some(true) {
|
if let Some(enabled) = value.active_window_border {
|
||||||
if BORDER_HWND.load(Ordering::SeqCst) == 0 {
|
border_manager::BORDER_ENABLED.store(enabled, Ordering::SeqCst);
|
||||||
Border::create("komorebi-border-window")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
BORDER_ENABLED.store(true, Ordering::SeqCst);
|
|
||||||
wm.show_border()?;
|
|
||||||
} else {
|
|
||||||
BORDER_ENABLED.store(false, Ordering::SeqCst);
|
|
||||||
wm.hide_border()?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(val) = value.window_container_behaviour {
|
if let Some(val) = value.window_container_behaviour {
|
||||||
|
|||||||
@@ -39,7 +39,8 @@ use komorebi_core::Rect;
|
|||||||
use komorebi_core::Sizing;
|
use komorebi_core::Sizing;
|
||||||
use komorebi_core::WindowContainerBehaviour;
|
use komorebi_core::WindowContainerBehaviour;
|
||||||
|
|
||||||
use crate::border::Border;
|
use crate::border_manager;
|
||||||
|
use crate::border_manager::STYLE;
|
||||||
use crate::container::Container;
|
use crate::container::Container;
|
||||||
use crate::current_virtual_desktop;
|
use crate::current_virtual_desktop;
|
||||||
use crate::load_configuration;
|
use crate::load_configuration;
|
||||||
@@ -55,14 +56,6 @@ use crate::ActiveWindowBorderColours;
|
|||||||
use crate::Colour;
|
use crate::Colour;
|
||||||
use crate::Rgb;
|
use crate::Rgb;
|
||||||
use crate::WorkspaceRule;
|
use crate::WorkspaceRule;
|
||||||
use crate::ACTIVE_WINDOW_BORDER_STYLE;
|
|
||||||
use crate::BORDER_COLOUR_MONOCLE;
|
|
||||||
use crate::BORDER_COLOUR_SINGLE;
|
|
||||||
use crate::BORDER_COLOUR_STACK;
|
|
||||||
use crate::BORDER_ENABLED;
|
|
||||||
use crate::BORDER_HWND;
|
|
||||||
use crate::BORDER_OFFSET;
|
|
||||||
use crate::BORDER_WIDTH;
|
|
||||||
use crate::CUSTOM_FFM;
|
use crate::CUSTOM_FFM;
|
||||||
use crate::DATA_DIR;
|
use crate::DATA_DIR;
|
||||||
use crate::DISPLAY_INDEX_PREFERENCES;
|
use crate::DISPLAY_INDEX_PREFERENCES;
|
||||||
@@ -153,15 +146,24 @@ pub struct GlobalState {
|
|||||||
impl Default for GlobalState {
|
impl Default for GlobalState {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
active_window_border_enabled: BORDER_ENABLED.load(Ordering::SeqCst),
|
active_window_border_enabled: border_manager::BORDER_ENABLED.load(Ordering::SeqCst),
|
||||||
active_window_border_colours: ActiveWindowBorderColours {
|
active_window_border_colours: ActiveWindowBorderColours {
|
||||||
single: Colour::Rgb(Rgb::from(BORDER_COLOUR_SINGLE.load(Ordering::SeqCst))),
|
single: Option::from(Colour::Rgb(Rgb::from(
|
||||||
stack: Colour::Rgb(Rgb::from(BORDER_COLOUR_STACK.load(Ordering::SeqCst))),
|
border_manager::FOCUSED.load(Ordering::SeqCst),
|
||||||
monocle: Colour::Rgb(Rgb::from(BORDER_COLOUR_MONOCLE.load(Ordering::SeqCst))),
|
))),
|
||||||
|
stack: Option::from(Colour::Rgb(Rgb::from(
|
||||||
|
border_manager::STACK.load(Ordering::SeqCst),
|
||||||
|
))),
|
||||||
|
monocle: Option::from(Colour::Rgb(Rgb::from(
|
||||||
|
border_manager::MONOCLE.load(Ordering::SeqCst),
|
||||||
|
))),
|
||||||
|
unfocused: Option::from(Colour::Rgb(Rgb::from(
|
||||||
|
border_manager::UNFOCUSED.load(Ordering::SeqCst),
|
||||||
|
))),
|
||||||
},
|
},
|
||||||
active_window_border_style: *ACTIVE_WINDOW_BORDER_STYLE.lock(),
|
active_window_border_style: *STYLE.lock(),
|
||||||
border_offset: BORDER_OFFSET.load(Ordering::SeqCst),
|
border_offset: border_manager::BORDER_OFFSET.load(Ordering::SeqCst),
|
||||||
border_width: BORDER_WIDTH.load(Ordering::SeqCst),
|
border_width: border_manager::BORDER_WIDTH.load(Ordering::SeqCst),
|
||||||
stackbar_mode: *STACKBAR_MODE.lock(),
|
stackbar_mode: *STACKBAR_MODE.lock(),
|
||||||
stackbar_focused_text_colour: Colour::Rgb(Rgb::from(
|
stackbar_focused_text_colour: Colour::Rgb(Rgb::from(
|
||||||
STACKBAR_FOCUSED_TEXT_COLOUR.load(Ordering::SeqCst),
|
STACKBAR_FOCUSED_TEXT_COLOUR.load(Ordering::SeqCst),
|
||||||
@@ -286,28 +288,6 @@ impl WindowManager {
|
|||||||
WindowsApi::load_workspace_information(&mut self.monitors)
|
WindowsApi::load_workspace_information(&mut self.monitors)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
|
||||||
pub fn show_border(&self) -> Result<()> {
|
|
||||||
if self.focused_container().is_ok() {
|
|
||||||
let foreground = WindowsApi::foreground_window()?;
|
|
||||||
let foreground_window = Window { hwnd: foreground };
|
|
||||||
|
|
||||||
let border = Border::from(BORDER_HWND.load(Ordering::SeqCst));
|
|
||||||
border.set_position(foreground_window, true)?;
|
|
||||||
WindowsApi::invalidate_border_rect()?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tracing::instrument(skip(self))]
|
|
||||||
pub fn hide_border(&self) -> Result<()> {
|
|
||||||
let focused = self.focused_window()?;
|
|
||||||
let border = Border::from(BORDER_HWND.load(Ordering::SeqCst));
|
|
||||||
border.hide()?;
|
|
||||||
focused.focus(false)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tracing::instrument]
|
#[tracing::instrument]
|
||||||
pub fn reload_configuration() {
|
pub fn reload_configuration() {
|
||||||
tracing::info!("reloading configuration");
|
tracing::info!("reloading configuration");
|
||||||
|
|||||||
+12
-39
@@ -2,7 +2,6 @@ use std::collections::VecDeque;
|
|||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
use std::sync::atomic::Ordering;
|
|
||||||
|
|
||||||
use color_eyre::eyre::anyhow;
|
use color_eyre::eyre::anyhow;
|
||||||
use color_eyre::eyre::Error;
|
use color_eyre::eyre::Error;
|
||||||
@@ -34,7 +33,6 @@ use windows::Win32::Graphics::Gdi::CreateSolidBrush;
|
|||||||
use windows::Win32::Graphics::Gdi::EnumDisplayDevicesW;
|
use windows::Win32::Graphics::Gdi::EnumDisplayDevicesW;
|
||||||
use windows::Win32::Graphics::Gdi::EnumDisplayMonitors;
|
use windows::Win32::Graphics::Gdi::EnumDisplayMonitors;
|
||||||
use windows::Win32::Graphics::Gdi::GetMonitorInfoW;
|
use windows::Win32::Graphics::Gdi::GetMonitorInfoW;
|
||||||
use windows::Win32::Graphics::Gdi::InvalidateRect;
|
|
||||||
use windows::Win32::Graphics::Gdi::MonitorFromPoint;
|
use windows::Win32::Graphics::Gdi::MonitorFromPoint;
|
||||||
use windows::Win32::Graphics::Gdi::MonitorFromWindow;
|
use windows::Win32::Graphics::Gdi::MonitorFromWindow;
|
||||||
use windows::Win32::Graphics::Gdi::Rectangle;
|
use windows::Win32::Graphics::Gdi::Rectangle;
|
||||||
@@ -101,7 +99,6 @@ use windows::Win32::UI::WindowsAndMessaging::EDD_GET_DEVICE_INTERFACE_NAME;
|
|||||||
use windows::Win32::UI::WindowsAndMessaging::GWL_EXSTYLE;
|
use windows::Win32::UI::WindowsAndMessaging::GWL_EXSTYLE;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::GWL_STYLE;
|
use windows::Win32::UI::WindowsAndMessaging::GWL_STYLE;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::GW_HWNDNEXT;
|
use windows::Win32::UI::WindowsAndMessaging::GW_HWNDNEXT;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::HWND_BOTTOM;
|
|
||||||
use windows::Win32::UI::WindowsAndMessaging::HWND_TOP;
|
use windows::Win32::UI::WindowsAndMessaging::HWND_TOP;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::LWA_ALPHA;
|
use windows::Win32::UI::WindowsAndMessaging::LWA_ALPHA;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::LWA_COLORKEY;
|
use windows::Win32::UI::WindowsAndMessaging::LWA_COLORKEY;
|
||||||
@@ -124,6 +121,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::SYSTEM_PARAMETERS_INFO_UPDATE_FLAGS;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::WINDOW_LONG_PTR_INDEX;
|
use windows::Win32::UI::WindowsAndMessaging::WINDOW_LONG_PTR_INDEX;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::WM_CLOSE;
|
use windows::Win32::UI::WindowsAndMessaging::WM_CLOSE;
|
||||||
|
use windows::Win32::UI::WindowsAndMessaging::WM_DESTROY;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSW;
|
use windows::Win32::UI::WindowsAndMessaging::WNDCLASSW;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::WNDENUMPROC;
|
use windows::Win32::UI::WindowsAndMessaging::WNDENUMPROC;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::WS_DISABLED;
|
use windows::Win32::UI::WindowsAndMessaging::WS_DISABLED;
|
||||||
@@ -142,8 +140,6 @@ use crate::monitor::Monitor;
|
|||||||
use crate::ring::Ring;
|
use crate::ring::Ring;
|
||||||
use crate::set_window_position::SetWindowPosition;
|
use crate::set_window_position::SetWindowPosition;
|
||||||
use crate::windows_callbacks;
|
use crate::windows_callbacks;
|
||||||
use crate::BORDER_HWND;
|
|
||||||
use crate::TRANSPARENCY_COLOUR;
|
|
||||||
|
|
||||||
pub enum WindowsResult<T, E> {
|
pub enum WindowsResult<T, E> {
|
||||||
Err(E),
|
Err(E),
|
||||||
@@ -395,33 +391,9 @@ impl WindowsApi {
|
|||||||
Self::set_window_pos(hwnd, &Rect::default(), position, flags.bits())
|
Self::set_window_pos(hwnd, &Rect::default(), position, flags.bits())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn position_border_window(hwnd: HWND, layout: &Rect, activate: bool) -> Result<()> {
|
pub fn set_border_pos(hwnd: HWND, layout: &Rect, position: HWND) -> Result<()> {
|
||||||
let flags = if activate {
|
let flags = { SetWindowPosition::SHOW_WINDOW | SetWindowPosition::NO_ACTIVATE };
|
||||||
SetWindowPosition::SHOW_WINDOW | SetWindowPosition::NO_ACTIVATE
|
Self::set_window_pos(hwnd, layout, position, flags.bits())
|
||||||
} else {
|
|
||||||
SetWindowPosition::NO_ACTIVATE
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO(raggi): This leaves the window behind the active window, which
|
|
||||||
// can result e.g. single pixel window borders being invisible in the
|
|
||||||
// case of opaque window borders (e.g. EPIC Games Launcher). Ideally
|
|
||||||
// we'd be able to pass a parent window to place ourselves just in front
|
|
||||||
// of, however the SetWindowPos API explicitly ignores that parameter
|
|
||||||
// unless the window being positioned is being activated - and we don't
|
|
||||||
// want to activate the border window here. We can hopefully find a
|
|
||||||
// better workaround in the future.
|
|
||||||
// The trade-off chosen prevents the border window from sitting over the
|
|
||||||
// top of other pop-up dialogs such as a file picker dialog from
|
|
||||||
// Firefox. When adjusting this in the future, it's important to check
|
|
||||||
// those dialog cases.
|
|
||||||
Self::set_window_pos(hwnd, layout, HWND_TOP, flags.bits())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn hide_border_window(hwnd: HWND) -> Result<()> {
|
|
||||||
let flags = SetWindowPosition::HIDE_WINDOW;
|
|
||||||
|
|
||||||
let position = HWND_BOTTOM;
|
|
||||||
Self::set_window_pos(hwnd, &Rect::default(), position, flags.bits())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// set_window_pos calls SetWindowPos without any accounting for Window decorations.
|
/// set_window_pos calls SetWindowPos without any accounting for Window decorations.
|
||||||
@@ -461,6 +433,13 @@ impl WindowsApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn destroy_window(hwnd: HWND) -> Result<()> {
|
||||||
|
match Self::post_message(hwnd, WM_DESTROY, WPARAM(0), LPARAM(0)) {
|
||||||
|
Ok(()) => Ok(()),
|
||||||
|
Err(_) => Err(anyhow!("could not close window")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn hide_window(hwnd: HWND) {
|
pub fn hide_window(hwnd: HWND) {
|
||||||
Self::show_window(hwnd, SW_HIDE);
|
Self::show_window(hwnd, SW_HIDE);
|
||||||
}
|
}
|
||||||
@@ -963,7 +942,7 @@ impl WindowsApi {
|
|||||||
None,
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
SetLayeredWindowAttributes(hwnd, COLORREF(TRANSPARENCY_COLOUR), 0, LWA_COLORKEY)?;
|
SetLayeredWindowAttributes(hwnd, COLORREF(0), 0, LWA_COLORKEY)?;
|
||||||
|
|
||||||
hwnd
|
hwnd
|
||||||
}
|
}
|
||||||
@@ -1000,12 +979,6 @@ impl WindowsApi {
|
|||||||
.process()
|
.process()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn invalidate_border_rect() -> Result<()> {
|
|
||||||
unsafe { InvalidateRect(HWND(BORDER_HWND.load(Ordering::SeqCst)), None, false) }
|
|
||||||
.ok()
|
|
||||||
.process()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn alt_is_pressed() -> bool {
|
pub fn alt_is_pressed() -> bool {
|
||||||
let state = unsafe { GetKeyState(i32::from(VK_MENU.0)) };
|
let state = unsafe { GetKeyState(i32::from(VK_MENU.0)) };
|
||||||
#[allow(clippy::cast_sign_loss)]
|
#[allow(clippy::cast_sign_loss)]
|
||||||
|
|||||||
@@ -1,36 +1,21 @@
|
|||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::sync::atomic::Ordering;
|
|
||||||
use widestring::U16CStr;
|
use widestring::U16CStr;
|
||||||
|
|
||||||
use windows::Win32::Foundation::BOOL;
|
use windows::Win32::Foundation::BOOL;
|
||||||
use windows::Win32::Foundation::COLORREF;
|
|
||||||
use windows::Win32::Foundation::HWND;
|
use windows::Win32::Foundation::HWND;
|
||||||
use windows::Win32::Foundation::LPARAM;
|
use windows::Win32::Foundation::LPARAM;
|
||||||
use windows::Win32::Foundation::LRESULT;
|
use windows::Win32::Foundation::LRESULT;
|
||||||
use windows::Win32::Foundation::RECT;
|
use windows::Win32::Foundation::RECT;
|
||||||
use windows::Win32::Foundation::WPARAM;
|
use windows::Win32::Foundation::WPARAM;
|
||||||
use windows::Win32::Graphics::Gdi::BeginPaint;
|
|
||||||
use windows::Win32::Graphics::Gdi::CreatePen;
|
|
||||||
use windows::Win32::Graphics::Gdi::EndPaint;
|
|
||||||
use windows::Win32::Graphics::Gdi::Rectangle;
|
|
||||||
use windows::Win32::Graphics::Gdi::RoundRect;
|
|
||||||
use windows::Win32::Graphics::Gdi::SelectObject;
|
|
||||||
use windows::Win32::Graphics::Gdi::ValidateRect;
|
|
||||||
use windows::Win32::Graphics::Gdi::HDC;
|
use windows::Win32::Graphics::Gdi::HDC;
|
||||||
use windows::Win32::Graphics::Gdi::HMONITOR;
|
use windows::Win32::Graphics::Gdi::HMONITOR;
|
||||||
use windows::Win32::Graphics::Gdi::PAINTSTRUCT;
|
|
||||||
use windows::Win32::Graphics::Gdi::PS_INSIDEFRAME;
|
|
||||||
use windows::Win32::Graphics::Gdi::PS_SOLID;
|
|
||||||
use windows::Win32::UI::Accessibility::HWINEVENTHOOK;
|
use windows::Win32::UI::Accessibility::HWINEVENTHOOK;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::DefWindowProcW;
|
use windows::Win32::UI::WindowsAndMessaging::DefWindowProcW;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::PostQuitMessage;
|
|
||||||
use windows::Win32::UI::WindowsAndMessaging::DBT_DEVNODES_CHANGED;
|
use windows::Win32::UI::WindowsAndMessaging::DBT_DEVNODES_CHANGED;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::SPI_ICONVERTICALSPACING;
|
use windows::Win32::UI::WindowsAndMessaging::SPI_ICONVERTICALSPACING;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::SPI_SETWORKAREA;
|
use windows::Win32::UI::WindowsAndMessaging::SPI_SETWORKAREA;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::WM_DESTROY;
|
|
||||||
use windows::Win32::UI::WindowsAndMessaging::WM_DEVICECHANGE;
|
use windows::Win32::UI::WindowsAndMessaging::WM_DEVICECHANGE;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::WM_DISPLAYCHANGE;
|
use windows::Win32::UI::WindowsAndMessaging::WM_DISPLAYCHANGE;
|
||||||
use windows::Win32::UI::WindowsAndMessaging::WM_PAINT;
|
|
||||||
use windows::Win32::UI::WindowsAndMessaging::WM_SETTINGCHANGE;
|
use windows::Win32::UI::WindowsAndMessaging::WM_SETTINGCHANGE;
|
||||||
|
|
||||||
use crate::container::Container;
|
use crate::container::Container;
|
||||||
@@ -42,15 +27,8 @@ use crate::window_manager_event::WindowManagerEvent;
|
|||||||
use crate::windows_api::WindowsApi;
|
use crate::windows_api::WindowsApi;
|
||||||
use crate::winevent::WinEvent;
|
use crate::winevent::WinEvent;
|
||||||
use crate::winevent_listener;
|
use crate::winevent_listener;
|
||||||
use crate::ACTIVE_WINDOW_BORDER_STYLE;
|
|
||||||
use crate::BORDER_COLOUR_CURRENT;
|
|
||||||
use crate::BORDER_RECT;
|
|
||||||
use crate::BORDER_WIDTH;
|
|
||||||
use crate::DISPLAY_INDEX_PREFERENCES;
|
use crate::DISPLAY_INDEX_PREFERENCES;
|
||||||
use crate::MONITOR_INDEX_PREFERENCES;
|
use crate::MONITOR_INDEX_PREFERENCES;
|
||||||
use crate::TRANSPARENCY_COLOUR;
|
|
||||||
use crate::WINDOWS_11;
|
|
||||||
use komorebi_core::ActiveWindowBorderStyle;
|
|
||||||
|
|
||||||
pub extern "system" fn valid_display_monitors(
|
pub extern "system" fn valid_display_monitors(
|
||||||
hmonitor: HMONITOR,
|
hmonitor: HMONITOR,
|
||||||
@@ -204,62 +182,6 @@ pub extern "system" fn win_event_hook(
|
|||||||
.expect("could not send message on winevent_listener::event_tx");
|
.expect("could not send message on winevent_listener::event_tx");
|
||||||
}
|
}
|
||||||
|
|
||||||
pub extern "system" fn border_window(
|
|
||||||
window: HWND,
|
|
||||||
message: u32,
|
|
||||||
wparam: WPARAM,
|
|
||||||
lparam: LPARAM,
|
|
||||||
) -> LRESULT {
|
|
||||||
unsafe {
|
|
||||||
match message {
|
|
||||||
WM_PAINT => {
|
|
||||||
let border_rect = *BORDER_RECT.lock();
|
|
||||||
let mut ps = PAINTSTRUCT::default();
|
|
||||||
let hdc = BeginPaint(window, &mut ps);
|
|
||||||
let hpen = CreatePen(
|
|
||||||
PS_SOLID | PS_INSIDEFRAME,
|
|
||||||
BORDER_WIDTH.load(Ordering::SeqCst),
|
|
||||||
COLORREF(BORDER_COLOUR_CURRENT.load(Ordering::SeqCst)),
|
|
||||||
);
|
|
||||||
let hbrush = WindowsApi::create_solid_brush(TRANSPARENCY_COLOUR);
|
|
||||||
|
|
||||||
SelectObject(hdc, hpen);
|
|
||||||
SelectObject(hdc, hbrush);
|
|
||||||
// TODO(raggi): this is approximately the correct curvature for
|
|
||||||
// the top left of a Windows 11 window (DWMWCP_DEFAULT), but
|
|
||||||
// often the bottom right has a different shape. Furthermore if
|
|
||||||
// the window was made with DWMWCP_ROUNDSMALL then this is the
|
|
||||||
// wrong size. In the future we should read the DWM properties
|
|
||||||
// of windows and attempt to match appropriately.
|
|
||||||
match *ACTIVE_WINDOW_BORDER_STYLE.lock() {
|
|
||||||
ActiveWindowBorderStyle::System => {
|
|
||||||
if *WINDOWS_11 {
|
|
||||||
RoundRect(hdc, 0, 0, border_rect.right, border_rect.bottom, 20, 20);
|
|
||||||
} else {
|
|
||||||
Rectangle(hdc, 0, 0, border_rect.right, border_rect.bottom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
ActiveWindowBorderStyle::Rounded => {
|
|
||||||
RoundRect(hdc, 0, 0, border_rect.right, border_rect.bottom, 20, 20);
|
|
||||||
}
|
|
||||||
ActiveWindowBorderStyle::Square => {
|
|
||||||
Rectangle(hdc, 0, 0, border_rect.right, border_rect.bottom);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
EndPaint(window, &ps);
|
|
||||||
ValidateRect(window, None);
|
|
||||||
|
|
||||||
LRESULT(0)
|
|
||||||
}
|
|
||||||
WM_DESTROY => {
|
|
||||||
PostQuitMessage(0);
|
|
||||||
LRESULT(0)
|
|
||||||
}
|
|
||||||
_ => DefWindowProcW(window, message, wparam, lparam),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub extern "system" fn hidden_window(
|
pub extern "system" fn hidden_window(
|
||||||
window: HWND,
|
window: HWND,
|
||||||
message: u32,
|
message: u32,
|
||||||
|
|||||||
@@ -20,14 +20,14 @@ use komorebi_core::Layout;
|
|||||||
use komorebi_core::OperationDirection;
|
use komorebi_core::OperationDirection;
|
||||||
use komorebi_core::Rect;
|
use komorebi_core::Rect;
|
||||||
|
|
||||||
|
use crate::border_manager::BORDER_OFFSET;
|
||||||
|
use crate::border_manager::BORDER_WIDTH;
|
||||||
use crate::container::Container;
|
use crate::container::Container;
|
||||||
use crate::ring::Ring;
|
use crate::ring::Ring;
|
||||||
use crate::static_config::WorkspaceConfig;
|
use crate::static_config::WorkspaceConfig;
|
||||||
use crate::window::Window;
|
use crate::window::Window;
|
||||||
use crate::window::WindowDetails;
|
use crate::window::WindowDetails;
|
||||||
use crate::windows_api::WindowsApi;
|
use crate::windows_api::WindowsApi;
|
||||||
use crate::BORDER_OFFSET;
|
|
||||||
use crate::BORDER_WIDTH;
|
|
||||||
use crate::DEFAULT_CONTAINER_PADDING;
|
use crate::DEFAULT_CONTAINER_PADDING;
|
||||||
use crate::DEFAULT_WORKSPACE_PADDING;
|
use crate::DEFAULT_WORKSPACE_PADDING;
|
||||||
use crate::INITIAL_CONFIGURATION_LOADED;
|
use crate::INITIAL_CONFIGURATION_LOADED;
|
||||||
|
|||||||
Reference in New Issue
Block a user