Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: get is_focused value dynamically #191

Merged
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions examples/focused_window.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
use std::thread;
use xcap::Window;

fn main() {
thread::sleep(std::time::Duration::from_secs(3));

let windows = Window::all().unwrap();

loop {
windows.iter().filter(|w| w.is_focused()).for_each(|focused| {
println!(
"Focused Window:\n id: {}\n title: {}\n app_name: {}\n monitor: {:?}\n position: {:?}\n size {:?}\n state {:?}\n",
focused.id(),
focused.title(),
focused.app_name(),
focused.current_monitor().name(),
(focused.x(), focused.y(), focused.z()),
(focused.width(), focused.height()),
(focused.is_minimized(), focused.is_maximized(), focused.is_focused())
);
});

thread::sleep(std::time::Duration::from_secs(1));
}
}
22 changes: 11 additions & 11 deletions src/linux/impl_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ pub(crate) struct ImplWindow {
pub height: u32,
pub is_minimized: bool,
pub is_maximized: bool,
pub is_focused: bool,
}

fn get_atom(conn: &Connection, name: &str) -> XCapResult<Atom> {
Expand Down Expand Up @@ -80,14 +79,15 @@ pub fn get_window_pid(conn: &Connection, window: &Window) -> XCapResult<u32> {
.copied()
}

fn get_active_window_id(conn: &Connection) -> Option<u32> {
let active_window_atom = get_atom(conn, "_NET_ACTIVE_WINDOW").ok()?;
fn get_active_window_id() -> Option<u32> {
let (conn, _) = Connection::connect(None).ok()?;
let active_window_atom = get_atom(&conn, "_NET_ACTIVE_WINDOW").ok()?;
let setup = conn.get_setup();

for screen in setup.roots() {
let root_window = screen.root();
let active_window_id =
get_window_property(conn, root_window, active_window_atom, ATOM_NONE, 0, 4).ok()?;
get_window_property(&conn, root_window, active_window_atom, ATOM_NONE, 0, 4).ok()?;
if let Some(&active_window_id) = active_window_id.value::<u32>().first() {
return Some(active_window_id);
}
Expand All @@ -102,7 +102,6 @@ impl ImplWindow {
window: &Window,
pid: u32,
z: i32,
is_focused: bool,
impl_monitors: &Vec<ImplMonitor>,
) -> XCapResult<ImplWindow> {
let title = {
Expand Down Expand Up @@ -215,10 +214,15 @@ impl ImplWindow {
height,
is_minimized,
is_maximized,
is_focused,
})
}

pub fn is_focused(&self) -> bool {
let active_window_id = get_active_window_id();

active_window_id.eq(&Some(self.pid))
}

pub fn all() -> XCapResult<Vec<ImplWindow>> {
let (conn, _) = Connection::connect(None)?;
let setup = conn.get_setup();
Expand All @@ -227,7 +231,6 @@ impl ImplWindow {
// https://specifications.freedesktop.org/wm-spec/1.5/ar01s03.html#id-1.4.4
// list all windows by stacking order
let client_list_atom = get_atom(&conn, "_NET_CLIENT_LIST_STACKING")?;
let active_window_id = get_active_window_id(&conn);

let mut impl_windows = Vec::new();
let impl_monitors = ImplMonitor::all()?;
Expand Down Expand Up @@ -267,10 +270,7 @@ impl ImplWindow {
}
};

let is_focused = active_window_id.eq(&Some(client.resource_id()));

if let Ok(impl_window) =
ImplWindow::new(&conn, client, pid, z, is_focused, &impl_monitors)
if let Ok(impl_window) = ImplWindow::new(&conn, client, pid, z, &impl_monitors)
{
impl_windows.push(impl_window);
} else {
Expand Down
25 changes: 15 additions & 10 deletions src/macos/impl_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use objc2_core_graphics::{
CGDisplayBounds, CGMainDisplayID, CGRectContainsPoint, CGRectIntersectsRect,
CGRectMakeWithDictionaryRepresentation, CGWindowListCopyWindowInfo, CGWindowListOption,
};
use objc2_foundation::{NSNumber, NSString};

use crate::{error::XCapResult, XCapError};

Expand All @@ -30,7 +31,6 @@ pub(crate) struct ImplWindow {
pub height: u32,
pub is_minimized: bool,
pub is_maximized: bool,
pub is_focused: bool,
}

unsafe impl Send for ImplWindow {}
Expand Down Expand Up @@ -117,7 +117,6 @@ impl ImplWindow {
window_name: String,
window_owner_name: String,
z: i32,
focused_app_pid: Option<i32>,
) -> XCapResult<ImplWindow> {
let id = get_cf_number_i32_value(window_cf_dictionary, "kCGWindowNumber")? as u32;
let pid = get_cf_number_i32_value(window_cf_dictionary, "kCGWindowOwnerPID")?;
Expand Down Expand Up @@ -154,8 +153,6 @@ impl ImplWindow {
let is_minimized =
!get_cf_bool_value(window_cf_dictionary, "kCGWindowIsOnscreen")? && !is_maximized;

let is_focused = focused_app_pid.eq(&Some(pid));

Ok(ImplWindow {
id,
title: window_name,
Expand All @@ -169,17 +166,26 @@ impl ImplWindow {
height: cg_rect.size.height as u32,
is_minimized,
is_maximized,
is_focused,
})
}

pub fn is_focused(&self) -> bool {
let focused_app_pid = unsafe {
let workspace = NSWorkspace::sharedWorkspace();
let pid_key = NSString::from_str("NSApplicationProcessIdentifier");
workspace
.activeApplication()
.and_then(|dictionary| dictionary.valueForKey(&pid_key))
.and_then(|pid| pid.downcast::<NSNumber>().ok())
.map(|pid| pid.intValue())
};

focused_app_pid.eq(&Some(self.pid as i32))
}

pub fn all() -> XCapResult<Vec<ImplWindow>> {
unsafe {
let impl_monitors = ImplMonitor::all()?;
let workspace = NSWorkspace::sharedWorkspace();
let focused_app_pid = workspace
.frontmostApplication()
.map(|focused_app| focused_app.processIdentifier());

let mut impl_windows = Vec::new();

Expand Down Expand Up @@ -236,7 +242,6 @@ impl ImplWindow {
window_name.clone(),
window_owner_name.clone(),
num_windows as i32 - i as i32 - 1,
focused_app_pid,
) {
impl_windows.push(impl_window);
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ impl Window {
}
/// The window is focused.
pub fn is_focused(&self) -> bool {
self.impl_window.is_focused
self.impl_window.is_focused()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't get the value from a function, we get the focused app when the Window has been built. now we get if the value is focused at the time of checking instead of a static value

}
}

Expand Down
8 changes: 4 additions & 4 deletions src/windows/impl_window.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,6 @@ pub(crate) struct ImplWindow {
pub height: u32,
pub is_minimized: bool,
pub is_maximized: bool,
pub is_focused: bool,
}

fn is_window_cloaked(hwnd: HWND) -> bool {
unsafe {
Expand Down Expand Up @@ -330,7 +328,6 @@ impl ImplWindow {
let rc_client = window_info.rcClient;
let is_minimized = IsIconic(hwnd).as_bool();
let is_maximized = IsZoomed(hwnd).as_bool();
let is_focused = GetForegroundWindow() == hwnd;

Ok(ImplWindow {
hwnd,
Expand All @@ -347,11 +344,14 @@ impl ImplWindow {
height: (rc_client.bottom - rc_client.top) as u32,
is_minimized,
is_maximized,
is_focused,
})
}
}

pub fn is_focused(&self) -> bool {
unsafe { GetForegroundWindow() == self.hwnd }
}

pub fn all() -> XCapResult<Vec<ImplWindow>> {
// (HWND, i32) 表示当前窗口以及层级,既(窗口,层级 z),i32 表示 max_z_order,既最大的窗口的 z 顺序
// 窗口当前层级为 max_z_order - z
Expand Down