1.1, Implemented untested focus_target functionality

main
isark 2 years ago
parent ec264eb07b
commit 75cf8df0d9

@ -1,6 +1,6 @@
[package]
name = "Underlayer"
version = "0.1.0"
version = "0.1.1"
edition = "2021"
# 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 }
}
pub fn focus_target() {
platform_impl::focus_target();
}
pub fn register<T: Into<String>>(window_title: T) -> Receiver<UnderlayEvent> {
let (tx,rx) = std::sync::mpsc::channel();

@ -1,8 +1,10 @@
use std::sync::{atomic::AtomicPtr, Arc, Mutex};
use x11rb::{
connect,
connection::Connection,
protocol::{
xproto::{Atom, AtomEnum, ChangeWindowAttributesAux, ConnectionExt, EventMask, Window},
xproto::{Atom, AtomEnum, ChangeWindowAttributesAux, ConnectionExt, EventMask, Window, InputFocus},
Event,
},
rust_connection::RustConnection,
@ -12,6 +14,10 @@ use crate::{Bounds, UnderlayEvent};
const WM_NAME_BUFSIZE: u32 = 512;
static TARGET: AtomicPtr<Arc<Mutex<Window>>> =
AtomicPtr::new(std::ptr::null_mut());
struct Target {
title: String,
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 {
conn: RustConnection,
root: Window,
@ -64,7 +84,8 @@ struct Runtime {
impl Runtime {
fn get_active_window(&self) -> Option<Window> {
let cookie = self.conn
let cookie = self
.conn
.get_property(
false,
self.root,
@ -74,14 +95,26 @@ impl Runtime {
1,
)
.ok()?;
let reply = cookie.reply().ok()?;
let mut value32_iter = reply.value32()?;
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> {
if wid == x11rb::NONE {
return None;
@ -187,16 +220,21 @@ impl Runtime {
}
if self.target.is_destroyed {
self.target.wid = x11rb::NONE;
self.set_target(x11rb::NONE);
self.target.is_destroyed = false;
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) {
Some(title) => {
if title != self.target.title {return}
if title != self.target.title {
return;
}
}
_ => return,
}
@ -212,7 +250,7 @@ impl Runtime {
.ok();
}
self.target.wid = wid;
self.set_target(wid);
self.conn
.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) {
@ -340,14 +378,19 @@ pub fn init(
runtime.active = runtime.get_active_window().unwrap_or(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.conn.flush().ok();
log::trace!("Initialized, listning for events");
while let Ok(event) = runtime.conn.wait_for_event() {
log::trace!("Got event");
runtime.handle_event(event);

@ -1,9 +1,7 @@
use windows::Win32::Graphics::Gdi::ClientToScreen;
use windows::Win32::System::Com::VT_I4;
use windows::Win32::System::Ole::{VariantClear, VariantInit};
use windows::Win32::UI::Accessibility::{
AccessibleObjectFromEvent, IAccessible,
};
use windows::Win32::UI::Accessibility::{AccessibleObjectFromEvent, IAccessible};
use std::sync::atomic::AtomicPtr;
use std::sync::{Arc, Mutex};
@ -14,9 +12,10 @@ use windows::Win32::Foundation::{
use windows::Win32::UI::WindowsAndMessaging::{
DispatchMessageW, GetClientRect, GetForegroundWindow, GetMessageW, GetWindowTextW,
GetWindowThreadProcessId, IsHungAppWindow, PostMessageW, RegisterWindowMessageW,
TranslateMessage, CHILDID_SELF, EVENT_OBJECT_DESTROY, EVENT_OBJECT_LOCATIONCHANGE,
EVENT_OBJECT_NAMECHANGE, EVENT_SYSTEM_FOREGROUND, EVENT_SYSTEM_MINIMIZEEND, MSG,
OBJECT_IDENTIFIER, OBJID_WINDOW, STATE_SYSTEM_FOCUSED, WINEVENT_OUTOFCONTEXT, SetTimer,
SetForegroundWindow, SetTimer, TranslateMessage, CHILDID_SELF, EVENT_OBJECT_DESTROY,
EVENT_OBJECT_LOCATIONCHANGE, EVENT_OBJECT_NAMECHANGE, EVENT_SYSTEM_FOREGROUND,
EVENT_SYSTEM_MINIMIZEEND, MSG, OBJECT_IDENTIFIER, OBJID_WINDOW, STATE_SYSTEM_FOCUSED,
WINEVENT_OUTOFCONTEXT,
};
use windows::Win32::{
Foundation::HWND,
@ -25,9 +24,21 @@ use windows::Win32::{
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());
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 {
match value {
EVENT_OBJECT_DESTROY => "EVENT_OBJECT_DESTROY".into(),
@ -171,7 +182,7 @@ unsafe extern "system" fn global_hook(
_dwmseventtime: u32,
) {
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(
event,
@ -189,7 +200,7 @@ unsafe extern "system" fn global_timer_hook(
_dwms_event_time: u32,
) {
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();
if runtime.foreground_window != system_foreground_window
@ -373,7 +384,11 @@ impl Runtime {
if let Some(bounds) = self.get_content_bounds() {
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();
self.target.is_focused = true;
@ -381,7 +396,6 @@ impl Runtime {
} else {
self.target.hwnd = Default::default();
}
}
fn msaa_check_window_focused_state(&mut self, hwnd: HWND) -> bool {
@ -497,9 +511,16 @@ pub fn init(
};
runtime.foreground_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)))),
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 result = unsafe { RegisterWindowMessageW(PCWSTR(message_wide.as_wide().as_ptr())) };
result
}
}

Loading…
Cancel
Save