【发布时间】:2020-09-03 01:24:07
【问题描述】:
正如标题所说。我正在使用 xcb 库在 Rust 中编写自定义 X11 窗口管理器。一个特定的窗口——cairo-dock 的“配置”窗口——在获得焦点时不会点击按钮 1,尽管取消了该窗口上的按钮 1。
以前,我认为所说的窗口没有保持焦点,但事实证明这是不正确的。相反,有问题的窗口正在接收焦点,但不允许单击任何按钮 1。
设置焦点的相关代码:
#[allow(clippy::single_match)]
fn set_focus(&mut self, window: xproto::Window) {
if window != self.root && window != self.focus {
let prev = self.focus;
// ungrab focus from the previous window
xproto::ungrab_button(
self.conn,
xproto::BUTTON_INDEX_1 as u8,
self.focus,
0
);
// make sure we don't accidentally have button 1 grabbed
xproto::ungrab_button(
self.conn,
xproto::BUTTON_INDEX_1 as u8,
window,
0
);
// See https://github.com/i3/i3/blob/b61a28f156aad545d5c54b9a6f40ef7cae1a1c9b/src/x.c#L1286-L1337
if self.needs_take_focus(window)
&& self.doesnt_take_focus(window)
&& window != base::NONE
&& window != self.root {
let client_message =
xproto::ClientMessageEvent::new(
32,
window,
self.atom("WM_PROTOCOLS"),
xproto::ClientMessageData::from_data32(
[
self.atom("WM_TAKE_FOCUS"),
self.last_timestamp,
0,
0,
0
]
)
);
xproto::send_event(self.conn, false, window, base::NONE as u32, &client_message);
} else {
debug!("{} can be focused normally", window);
xproto::set_input_focus(
self.conn,
xproto::INPUT_FOCUS_PARENT as u8,
window,
self.last_timestamp,
);
}
self.replace_prop(
self.root,
self.atom("_NET_ACTIVE_WINDOW"),
32,
&[window]
);
debug!("updating _NET_WM_STATE with _NET_WM_STATE_FOCUSED!");
self.remove_prop(prev, self.atom("_NET_WM_STATE"), self.atom("_NET_WM_STATE_FOCUSED"));
self.append_prop(window, self.atom("_NET_WM_STATE"), self.atom("_NET_WM_STATE_FOCUSED"));
self.focus = window;
debug!("focused window: {}", self.focus);
} else if window == self.root {
self.remove_prop(self.focus, self.atom("_NET_WM_STATE"), self.atom("_NET_WM_STATE_FOCUSED"));
debug!("focusing root -> NONE");
self.replace_prop(self.root, self.atom("_NET_ACTIVE_WINDOW"), 32, &[base::NONE]);
xproto::set_input_focus(self.conn, 0, base::NONE, base::CURRENT_TIME);
self.focus = xcb::NONE;
}
}
fn append_prop(&self, window: xproto::Window, prop: u32, atom: u32) {
// TODO: Check result
xproto::change_property(
self.conn,
xproto::PROP_MODE_APPEND as u8,
window,
prop,
xproto::ATOM_ATOM,
32,
&[atom]
);
}
fn remove_prop(&self, window: xproto::Window, prop: u32, atom: u32) {
let cookie = xproto::get_property(self.conn, false, window, prop, xproto::GET_PROPERTY_TYPE_ANY, 0, 4096);
match cookie.get_reply() {
Ok(res) => {
match res.value::<u32>() {
[] => {},
values => {
let mut new_values: Vec<u32> = Vec::from(values);
new_values.retain(|value| value != &atom);
self.replace_prop(window, prop, 32, &new_values);
},
}
},
Err(err) => error!("couldn't get props to remove from: {:#?}", err),
}
}
fn needs_take_focus(&self, window: xproto::Window) -> bool {
let properties_cookie =
xproto::get_property(
self.conn,
false,
window,
self.atom("WM_PROTOCOLS"),
xproto::ATOM_ANY,
0,
2048
);
match properties_cookie.get_reply() {
Ok(protocols) => {
let mut needs_help = false;
for proto in protocols.value::<u32>().iter() {
match self.atom_by_id_checked(proto) {
Some("WM_TAKE_FOCUS") => {
needs_help = true
},
_ => (),
}
}
needs_help
},
// FIXME
Err(_) => false,
}
}
fn doesnt_take_focus(&self, window: xproto::Window) -> bool {
match xcb_util::icccm::get_wm_hints(self.conn, window).get_reply() {
Ok(hints) => {
if let Some(input) = hints.input() {
input
} else {
false
}
},
// FIXME
Err(_) => false,
}
}
【问题讨论】:
-
“无法对焦”到底是什么意思?是“当我输入文本时,它不会出现在窗口的文本字段中”还是“窗口没有呈现为具有焦点”?另外,您是否检查过窗口本身是否将焦点放在其他东西上?如:您是否收到
FocusNotify窗口事件,然后是其他事件? -
另外,您对如何设置焦点的描述对我来说似乎很奇怪。没有
WM_FOCUS。如果窗口支持WM_TAKE_FOCUS协议,则向它发送WM_TAKE_FOCUS消息(带有当前时间戳)。如果窗口的WM_HINTS中有input,则发送SetInputFocus消息。这两个条件是独立的。这意味着如果两个条件都为真等,你就两者都做。 -
最后:您能否显示/链接到您的代码?你有问题窗口的
xprop输出吗? (WM_TAKE_FOCUS和WM_HINTS中的input字段中的哪一个在这里是“特殊的”?) -
非常感谢您的帮助!我不是一直到那里,但是在我深夜编码之后,这为我指明了正确的方向:) 1. “无法集中注意力”似乎错误地描述了这个问题;进一步的测试表明,实际上只是输入事件(专门按下按钮 1)没有发送到窗口;按键事件和类似事件实际上按预期工作。 2. 对,那是一个深夜的错字;我的意思是
WM_TAKE_FOCUS。我正在查看 i3 的工作原理:github.com/i3/i3/blob/b61a28f156aad545d5c54b9a6f40ef7cae1a1c9b/… 3. 我已经在我的代码中进行了编辑。 -
事实证明,我最初对这个问题的看法是不正确的。我已经编辑了我的问题,以更准确地反映正在发生的事情。
标签: rust window-managers xcb ewmh icccm