1.1, Implemented untested focus_target functionality

main
isark 2 years ago
parent ec264eb07b
commit 75cf8df0d9

@ -1,6 +1,6 @@
[package] [package]
name = "Underlayer" name = "Underlayer"
version = "0.1.0" version = "0.1.1"
edition = "2021" edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

@ -28,6 +28,10 @@ pub enum UnderlayEvent {
X11FullscreenEvent{ is_fullscreen: bool } X11FullscreenEvent{ is_fullscreen: bool }
} }
pub fn focus_target() {
platform_impl::focus_target();
}
pub fn register<T: Into<String>>(window_title: T) -> Receiver<UnderlayEvent> { pub fn register<T: Into<String>>(window_title: T) -> Receiver<UnderlayEvent> {
let (tx,rx) = std::sync::mpsc::channel(); let (tx,rx) = std::sync::mpsc::channel();

@ -1,8 +1,10 @@
use std::sync::{atomic::AtomicPtr, Arc, Mutex};
use x11rb::{ use x11rb::{
connect, connect,
connection::Connection, connection::Connection,
protocol::{ protocol::{
xproto::{Atom, AtomEnum, ChangeWindowAttributesAux, ConnectionExt, EventMask, Window}, xproto::{Atom, AtomEnum, ChangeWindowAttributesAux, ConnectionExt, EventMask, Window, InputFocus},
Event, Event,
}, },
rust_connection::RustConnection, rust_connection::RustConnection,
@ -12,6 +14,10 @@ use crate::{Bounds, UnderlayEvent};
const WM_NAME_BUFSIZE: u32 = 512; const WM_NAME_BUFSIZE: u32 = 512;
static TARGET: AtomicPtr<Arc<Mutex<Window>>> =
AtomicPtr::new(std::ptr::null_mut());
struct Target { struct Target {
title: String, title: String,
wid: Window, wid: Window,
@ -53,6 +59,20 @@ impl AtomCollection {
} }
} }
pub fn focus_target() {
unsafe {
if let Ok(target) =
(*TARGET.load(std::sync::atomic::Ordering::Relaxed)).lock()
{
if *target != x11rb::NONE {
if let Ok((conn, _)) = connect(None) {
conn.set_input_focus(InputFocus::PARENT, *target, x11rb::CURRENT_TIME).ok();
}
}
}
}
}
struct Runtime { struct Runtime {
conn: RustConnection, conn: RustConnection,
root: Window, root: Window,
@ -64,7 +84,8 @@ struct Runtime {
impl Runtime { impl Runtime {
fn get_active_window(&self) -> Option<Window> { fn get_active_window(&self) -> Option<Window> {
let cookie = self.conn let cookie = self
.conn
.get_property( .get_property(
false, false,
self.root, self.root,
@ -74,14 +95,26 @@ impl Runtime {
1, 1,
) )
.ok()?; .ok()?;
let reply = cookie.reply().ok()?; let reply = cookie.reply().ok()?;
let mut value32_iter = reply.value32()?; let mut value32_iter = reply.value32()?;
value32_iter.next() value32_iter.next()
} }
///Using this instead to allow setting the globally accessible target too for focus_target.
fn set_target(&mut self, wid: Window) {
self.target.wid = wid;
unsafe {
if let Ok(mut target) =
(*TARGET.load(std::sync::atomic::Ordering::Relaxed)).lock()
{
*target = wid;
}
}
}
fn get_title(&self, wid: Window) -> Option<String> { fn get_title(&self, wid: Window) -> Option<String> {
if wid == x11rb::NONE { if wid == x11rb::NONE {
return None; return None;
@ -187,16 +220,21 @@ impl Runtime {
} }
if self.target.is_destroyed { if self.target.is_destroyed {
self.target.wid = x11rb::NONE; self.set_target(x11rb::NONE);
self.target.is_destroyed = false; self.target.is_destroyed = false;
self.underlay_tx.send(UnderlayEvent::Detach).ok(); self.underlay_tx.send(UnderlayEvent::Detach).ok();
} }
} }
log::trace!("got title: {}", self.get_title(wid).unwrap_or("ERROR".into())); log::trace!(
"got title: {}",
self.get_title(wid).unwrap_or("ERROR".into())
);
match self.get_title(wid) { match self.get_title(wid) {
Some(title) => { Some(title) => {
if title != self.target.title {return} if title != self.target.title {
return;
}
} }
_ => return, _ => return,
} }
@ -212,7 +250,7 @@ impl Runtime {
.ok(); .ok();
} }
self.target.wid = wid; self.set_target(wid);
self.conn self.conn
.change_window_attributes( .change_window_attributes(
@ -241,7 +279,7 @@ impl Runtime {
} }
} }
self.target.wid = x11rb::NONE; self.set_target(x11rb::NONE);
} }
fn handle_event(&mut self, event: Event) { fn handle_event(&mut self, event: Event) {
@ -340,14 +378,19 @@ pub fn init(
runtime.active = runtime.get_active_window().unwrap_or(x11rb::NONE); runtime.active = runtime.get_active_window().unwrap_or(x11rb::NONE);
if runtime.active != x11rb::NONE { if runtime.active != x11rb::NONE {
runtime.conn.change_window_attributes(runtime.active, &ChangeWindowAttributesAux::new().event_mask(EventMask::PROPERTY_CHANGE)).ok(); runtime
.conn
.change_window_attributes(
runtime.active,
&ChangeWindowAttributesAux::new().event_mask(EventMask::PROPERTY_CHANGE),
)
.ok();
runtime.check_and_handle_window(runtime.active); runtime.check_and_handle_window(runtime.active);
} }
runtime.conn.flush().ok(); runtime.conn.flush().ok();
log::trace!("Initialized, listning for events"); log::trace!("Initialized, listning for events");
while let Ok(event) = runtime.conn.wait_for_event() { while let Ok(event) = runtime.conn.wait_for_event() {
log::trace!("Got event"); log::trace!("Got event");
runtime.handle_event(event); runtime.handle_event(event);

@ -1,9 +1,7 @@
use windows::Win32::Graphics::Gdi::ClientToScreen; use windows::Win32::Graphics::Gdi::ClientToScreen;
use windows::Win32::System::Com::VT_I4; use windows::Win32::System::Com::VT_I4;
use windows::Win32::System::Ole::{VariantClear, VariantInit}; use windows::Win32::System::Ole::{VariantClear, VariantInit};
use windows::Win32::UI::Accessibility::{ use windows::Win32::UI::Accessibility::{AccessibleObjectFromEvent, IAccessible};
AccessibleObjectFromEvent, IAccessible,
};
use std::sync::atomic::AtomicPtr; use std::sync::atomic::AtomicPtr;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
@ -14,9 +12,10 @@ use windows::Win32::Foundation::{
use windows::Win32::UI::WindowsAndMessaging::{ use windows::Win32::UI::WindowsAndMessaging::{
DispatchMessageW, GetClientRect, GetForegroundWindow, GetMessageW, GetWindowTextW, DispatchMessageW, GetClientRect, GetForegroundWindow, GetMessageW, GetWindowTextW,
GetWindowThreadProcessId, IsHungAppWindow, PostMessageW, RegisterWindowMessageW, GetWindowThreadProcessId, IsHungAppWindow, PostMessageW, RegisterWindowMessageW,
TranslateMessage, CHILDID_SELF, EVENT_OBJECT_DESTROY, EVENT_OBJECT_LOCATIONCHANGE, SetForegroundWindow, SetTimer, TranslateMessage, CHILDID_SELF, EVENT_OBJECT_DESTROY,
EVENT_OBJECT_NAMECHANGE, EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_MINIMIZEEND, MSG, EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_NAMECHANGE, EVENT_SYSTEM_FOREGROUND,
OBJECT_IDENTIFIER, OBJID_WINDOW, STATE_SYSTEM_FOCUSED, WINEVENT_OUTOFCONTEXT, SetTimer, EVENT_SYSTEM_MINIMIZEEND, MSG, OBJECT_IDENTIFIER, OBJID_WINDOW, STATE_SYSTEM_FOCUSED,
WINEVENT_OUTOFCONTEXT,
}; };
use windows::Win32::{ use windows::Win32::{
Foundation::HWND, Foundation::HWND,
@ -25,9 +24,21 @@ use windows::Win32::{
use crate::{Bounds, UnderlayEvent}; use crate::{Bounds, UnderlayEvent};
static GLOBAL_CALLBACK_SENDER: AtomicPtr<Arc<Mutex<Runtime>>> = static GLOBAL_RUNTIME: AtomicPtr<Arc<Mutex<Runtime>>> =
AtomicPtr::new(std::ptr::null_mut()); AtomicPtr::new(std::ptr::null_mut());
pub fn focus_target() {
unsafe {
if let Ok(runtime) =
(*GLOBAL_RUNTIME.load(std::sync::atomic::Ordering::Relaxed)).lock()
{
if runtime.target.hwnd.is_valid() {
SetForegroundWindow(runtime.target.hwnd);
}
}
}
}
fn constant_name(value: u32) -> String { fn constant_name(value: u32) -> String {
match value { match value {
EVENT_OBJECT_DESTROY => "EVENT_OBJECT_DESTROY".into(), EVENT_OBJECT_DESTROY => "EVENT_OBJECT_DESTROY".into(),
@ -171,7 +182,7 @@ unsafe extern "system" fn global_hook(
_dwmseventtime: u32, _dwmseventtime: u32,
) { ) {
if let Ok(mut runtime) = if let Ok(mut runtime) =
(*GLOBAL_CALLBACK_SENDER.load(std::sync::atomic::Ordering::Relaxed)).lock() (*GLOBAL_RUNTIME.load(std::sync::atomic::Ordering::Relaxed)).lock()
{ {
runtime.on_event(Event::from_data( runtime.on_event(Event::from_data(
event, event,
@ -189,7 +200,7 @@ unsafe extern "system" fn global_timer_hook(
_dwms_event_time: u32, _dwms_event_time: u32,
) { ) {
if let Ok(mut runtime) = if let Ok(mut runtime) =
(*GLOBAL_CALLBACK_SENDER.load(std::sync::atomic::Ordering::Relaxed)).lock() (*GLOBAL_RUNTIME.load(std::sync::atomic::Ordering::Relaxed)).lock()
{ {
let system_foreground_window = GetForegroundWindow(); let system_foreground_window = GetForegroundWindow();
if runtime.foreground_window != system_foreground_window if runtime.foreground_window != system_foreground_window
@ -373,7 +384,11 @@ impl Runtime {
if let Some(bounds) = self.get_content_bounds() { if let Some(bounds) = self.get_content_bounds() {
self.underlay_tx self.underlay_tx
.send(UnderlayEvent::Attach { bounds, has_access: Some(has_access), is_fullscreen: None }) .send(UnderlayEvent::Attach {
bounds,
has_access: Some(has_access),
is_fullscreen: None,
})
.ok(); .ok();
self.target.is_focused = true; self.target.is_focused = true;
@ -381,7 +396,6 @@ impl Runtime {
} else { } else {
self.target.hwnd = Default::default(); self.target.hwnd = Default::default();
} }
} }
fn msaa_check_window_focused_state(&mut self, hwnd: HWND) -> bool { fn msaa_check_window_focused_state(&mut self, hwnd: HWND) -> bool {
@ -497,9 +511,16 @@ pub fn init(
}; };
runtime.foreground_change.bind(); runtime.foreground_change.bind();
runtime.unminimize_change.bind(); runtime.unminimize_change.bind();
unsafe { SetTimer(HWND::default(), 0, OW_FOREGROUND_TIMER_MS, Some(global_timer_hook)) }; unsafe {
SetTimer(
HWND::default(),
0,
OW_FOREGROUND_TIMER_MS,
Some(global_timer_hook),
)
};
GLOBAL_CALLBACK_SENDER.store( GLOBAL_RUNTIME.store(
Box::into_raw(Box::new(Arc::new(Mutex::new(runtime)))), Box::into_raw(Box::new(Arc::new(Mutex::new(runtime)))),
std::sync::atomic::Ordering::Relaxed, std::sync::atomic::Ordering::Relaxed,
); );
@ -522,4 +543,4 @@ fn register_message<T: Into<String>>(message: T) -> u32 {
let message_wide = windows::core::HSTRING::from(message.into()); let message_wide = windows::core::HSTRING::from(message.into());
let result = unsafe { RegisterWindowMessageW(PCWSTR(message_wide.as_wide().as_ptr())) }; let result = unsafe { RegisterWindowMessageW(PCWSTR(message_wide.as_wide().as_ptr())) };
result result
} }

Loading…
Cancel
Save