Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
90 changes: 75 additions & 15 deletions src/xwayland/xwm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ use crate::{
},
};
use atomic_float::AtomicF64;
use calloop::{Interest, LoopHandle, Mode, PostAction, generic::Generic};
use calloop::{Interest, LoopHandle, Mode, PostAction, generic::Generic, ping};
use rustix::fs::OFlags;
use std::{
cell::RefCell,
Expand All @@ -147,7 +147,10 @@ use std::{
io::{AsFd, OwnedFd},
net::UnixStream,
},
sync::{Arc, Weak, atomic::Ordering},
sync::{
Arc, Weak,
atomic::{AtomicBool, Ordering},
},
};
use tracing::{debug, debug_span, info, trace, warn};
use wayland_server::{DisplayHandle, Resource};
Expand All @@ -163,9 +166,9 @@ use x11rb::{
render::{ConnectionExt as _, CreatePictureAux, PictureWrapper},
xfixes::ConnectionExt as _,
xproto::{
AtomEnum, CONFIGURE_NOTIFY_EVENT, ChangeWindowAttributesAux, Colormap, ColormapAlloc,
Atom, AtomEnum, CONFIGURE_NOTIFY_EVENT, ChangeWindowAttributesAux, Colormap, ColormapAlloc,
ConfigWindow, ConfigureNotifyEvent, ConfigureWindowAux, ConnectionExt, CreateGCAux,
CreateWindowAux, CursorWrapper, EventMask, FontWrapper, GcontextWrapper, ImageFormat,
CreateWindowAux, CursorWrapper, EventMask, FontWrapper, GcontextWrapper, ImageFormat, InputFocus,
PixmapWrapper, PropMode, Property, QueryExtensionReply, Screen, StackMode, Visualid, WindowClass,
},
},
Expand Down Expand Up @@ -567,6 +570,8 @@ pub struct X11Wm {

is_showing_desktop: bool,

pub(super) focus_release: FocusReleaseHandle,

span: tracing::Span,
}

Expand All @@ -576,6 +581,64 @@ impl Drop for X11Wm {
}
}

#[derive(Debug, Clone)]
pub(super) struct FocusReleaseHandle {
pending: Arc<AtomicBool>,
signal: ping::Ping,
conn: Weak<RustConnection>,
root: X11Window,
active_window: Atom,
}

impl FocusReleaseHandle {
fn new(
conn: &Arc<RustConnection>,
root: X11Window,
active_window: Atom,
) -> std::io::Result<(Self, ping::PingSource)> {
let (signal, source) = ping::make_ping()?;
Ok((
Self {
pending: Arc::new(AtomicBool::new(false)),
signal,
conn: Arc::downgrade(conn),
root,
active_window,
},
source,
))
}

fn schedule(&self) {
self.pending.store(true, Ordering::Release);
self.signal.ping();
}

fn cancel(&self) {
self.pending.store(false, Ordering::Release);
}

fn dispatch(&self) {
if !self.pending.swap(false, Ordering::AcqRel) {
return;
}
let Some(conn) = self.conn.upgrade() else { return };
if let Err(err) = conn.set_input_focus(InputFocus::NONE, x11rb::NONE, x11rb::CURRENT_TIME) {
warn!("Unable to release X11 keyboard focus: {}", err);
}
if let Err(err) = conn.change_property32(
PropMode::REPLACE,
self.root,
self.active_window,
AtomEnum::WINDOW,
&[x11rb::NONE],
) {
warn!("Unable to clear _NET_ACTIVE_WINDOW: {}", err);
}
let _ = conn.flush();
}
}

/// Edge values for resizing
///
// These values are used to indicate which edge of a surface is being dragged in a resize operation.
Expand Down Expand Up @@ -890,6 +953,13 @@ impl X11Wm {
let dnd = XWmDnd::new(&conn, &screen, &atoms)?;
let wm_window = OwnedX11Window::new(win, &conn);

let (focus_release, focus_release_source) =
FocusReleaseHandle::new(&conn, screen.root, atoms._NET_ACTIVE_WINDOW)?;
{
let release = focus_release.clone();
handle.insert_source(focus_release_source, move |_, _, _| release.dispatch())?;
}

drop(_guard);
let wm = Self {
id,
Expand All @@ -911,6 +981,7 @@ impl X11Wm {
client_list: Vec::new(),
client_list_stacking: Vec::new(),
is_showing_desktop: false,
focus_release,
span,
};

Expand Down Expand Up @@ -2227,17 +2298,6 @@ where
)?;
}
}
Event::FocusOut(n) => {
if xwm.windows.iter().any(|x| x.window_id() == n.event) {
conn.change_property32(
PropMode::REPLACE,
xwm.screen.root,
xwm.atoms._NET_ACTIVE_WINDOW,
AtomEnum::WINDOW,
&[x11rb::NONE],
)?;
}
}
Event::ClientMessage(msg) => {
if let Some(reply) = conn.get_atom_name(msg.type_)?.reply_unchecked()? {
trace!(
Expand Down
15 changes: 10 additions & 5 deletions src/xwayland/xwm/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pub struct X11Surface {
xwm: Option<XwmId>,
client_scale: Option<Arc<AtomicF64>>,
window: X11Window,
focus_release: Option<super::FocusReleaseHandle>,
pub(super) conn: Weak<RustConnection>,
pub(super) atoms: super::Atoms,
pub(crate) state: Arc<Mutex<SharedSurfaceState>>,
Expand Down Expand Up @@ -269,6 +270,7 @@ impl X11Surface {
pending_ping_timestamp: None,
})),
xdnd_active,
focus_release: xwm.map(|wm| wm.focus_release.clone()),
user_data: Arc::new(UserDataMap::new()),
}
}
Expand Down Expand Up @@ -1375,6 +1377,10 @@ impl<D: SeatHandler + 'static> KeyboardTarget<D> for X11Surface {
WmInputModel::GloballyActive => (false, true),
};

if let Some(release) = &self.focus_release {
release.cancel();
}

if let Some(conn) = self.conn.upgrade() {
if set_input_focus {
if let Err(err) = conn.set_input_focus(InputFocus::NONE, self.window, x11rb::CURRENT_TIME) {
Expand Down Expand Up @@ -1417,11 +1423,10 @@ impl<D: SeatHandler + 'static> KeyboardTarget<D> for X11Surface {
fn leave(&self, seat: &Seat<D>, data: &mut D, serial: Serial) {
if self.input_model() == WmInputModel::None {
return;
} else if let Some(conn) = self.conn.upgrade() {
if let Err(err) = conn.set_input_focus(InputFocus::NONE, x11rb::NONE, x11rb::CURRENT_TIME) {
warn!("Unable to unfocus X11Surface ({:?}): {}", self.window, err);
}
let _ = conn.flush();
}

if let Some(release) = &self.focus_release {
release.schedule();
}

let mut state = self.state.lock().unwrap();
Expand Down
Loading