1
0
Fork 0
forked from wry/wry

xwayland: split window property loading

This commit is contained in:
kossLAN 2026-05-29 21:32:44 -04:00
parent 7531c8f791
commit ea7251d6e0
No known key found for this signature in database
3 changed files with 429 additions and 405 deletions

View file

@ -1,6 +1,7 @@
#![allow(clippy::await_holding_refcell_ref)] // all borrows are to data that is only used by this task #![allow(clippy::await_holding_refcell_ref)] // all borrows are to data that is only used by this task
mod selection; mod selection;
mod properties;
mod transfer; mod transfer;
use selection::SelectionData; use selection::SelectionData;
@ -9,7 +10,6 @@ use {
crate::{ crate::{
async_engine::SpawnedFuture, async_engine::SpawnedFuture,
client::Client, client::Client,
criteria::tlm::{TL_CHANGED_CLASS_INST, TL_CHANGED_ROLE},
ifs::{ ifs::{
data_transfer::{ data_transfer::{
DataOfferId, DataSourceId, DynDataOffer, DynDataSource, TransferLocation, TransferVtable, DataOfferId, DataSourceId, DynDataOffer, DynDataSource, TransferLocation, TransferVtable,
@ -22,7 +22,7 @@ use {
wl_seat::{SeatId, WlSeatGlobal}, wl_seat::{SeatId, WlSeatGlobal},
wl_surface::{ wl_surface::{
WlSurface, WlSurface,
x_surface::xwindow::{XInputModel, Xwindow, XwindowData}, x_surface::xwindow::{Xwindow, XwindowData},
}, },
}, },
rect::Rect, rect::Rect,
@ -46,7 +46,7 @@ use {
ChangeProperty, ChangeWindowAttributes, ClientMessage, CompositeRedirectSubwindows, ChangeProperty, ChangeWindowAttributes, ClientMessage, CompositeRedirectSubwindows,
ConfigureNotify, ConfigureRequest, ConfigureWindow, ConfigureWindowValues, ConfigureNotify, ConfigureRequest, ConfigureWindow, ConfigureWindowValues,
ConvertSelection, CreateNotify, CreateWindow, CreateWindowValues, DestroyNotify, ConvertSelection, CreateNotify, CreateWindow, CreateWindowValues, DestroyNotify,
Extension, FocusIn, GetAtomName, GetGeometry, InternAtom, KillClient, MapNotify, Extension, FocusIn, GetGeometry, InternAtom, KillClient, MapNotify,
MapRequest, MapWindow, PropertyNotify, ResClientIdSpec, ResQueryClientIds, MapRequest, MapWindow, PropertyNotify, ResClientIdSpec, ResQueryClientIds,
SelectSelectionInput, SelectionNotify, SelectionRequest, SetInputFocus, SelectSelectionInput, SelectionNotify, SelectionRequest, SetInputFocus,
SetSelectionOwner, UnmapNotify, XfixesQueryVersion, XfixesSelectionNotify, SetSelectionOwner, UnmapNotify, XfixesQueryVersion, XfixesSelectionNotify,
@ -56,14 +56,13 @@ use {
consts::{ consts::{
_NET_WM_STATE_ADD, _NET_WM_STATE_REMOVE, _NET_WM_STATE_TOGGLE, ATOM_ATOM, _NET_WM_STATE_ADD, _NET_WM_STATE_REMOVE, _NET_WM_STATE_TOGGLE, ATOM_ATOM,
ATOM_NONE, ATOM_STRING, ATOM_WINDOW, ATOM_WM_CLASS, ATOM_WM_NAME, ATOM_NONE, ATOM_STRING, ATOM_WINDOW, ATOM_WM_CLASS, ATOM_WM_NAME,
ATOM_WM_SIZE_HINTS, ATOM_WM_TRANSIENT_FOR, COMPOSITE_REDIRECT_MANUAL, ATOM_WM_TRANSIENT_FOR, COMPOSITE_REDIRECT_MANUAL, CONFIG_WINDOW_HEIGHT,
CONFIG_WINDOW_HEIGHT, CONFIG_WINDOW_WIDTH, CONFIG_WINDOW_X, CONFIG_WINDOW_Y, CONFIG_WINDOW_WIDTH, CONFIG_WINDOW_X, CONFIG_WINDOW_Y, EVENT_MASK_FOCUS_CHANGE,
EVENT_MASK_FOCUS_CHANGE, EVENT_MASK_PROPERTY_CHANGE, EVENT_MASK_PROPERTY_CHANGE, EVENT_MASK_SUBSTRUCTURE_NOTIFY,
EVENT_MASK_SUBSTRUCTURE_NOTIFY, EVENT_MASK_SUBSTRUCTURE_REDIRECT, EVENT_MASK_SUBSTRUCTURE_REDIRECT, ICCCM_WM_STATE_ICONIC, ICCCM_WM_STATE_NORMAL,
ICCCM_WM_HINT_INPUT, ICCCM_WM_STATE_ICONIC, ICCCM_WM_STATE_NORMAL, ICCCM_WM_STATE_WITHDRAWN, INPUT_FOCUS_POINTER_ROOT, NOTIFY_DETAIL_POINTER,
ICCCM_WM_STATE_WITHDRAWN, INPUT_FOCUS_POINTER_ROOT, MWM_HINTS_DECORATIONS_FIELD, NOTIFY_MODE_GRAB, NOTIFY_MODE_UNGRAB, PROP_MODE_REPLACE,
MWM_HINTS_FLAGS_FIELD, NOTIFY_DETAIL_POINTER, NOTIFY_MODE_GRAB, NOTIFY_MODE_UNGRAB, RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID, SELECTION_CLIENT_CLOSE_MASK,
PROP_MODE_REPLACE, RES_CLIENT_ID_MASK_LOCAL_CLIENT_PID, SELECTION_CLIENT_CLOSE_MASK,
SELECTION_WINDOW_DESTROY_MASK, SET_SELECTION_OWNER_MASK, STACK_MODE_ABOVE, SELECTION_WINDOW_DESTROY_MASK, SET_SELECTION_OWNER_MASK, STACK_MODE_ABOVE,
STACK_MODE_BELOW, WINDOW_CLASS_INPUT_OUTPUT, STACK_MODE_BELOW, WINDOW_CLASS_INPUT_OUTPUT,
}, },
@ -71,7 +70,7 @@ use {
xwayland::{XWaylandError, XWaylandEvent}, xwayland::{XWaylandError, XWaylandEvent},
}, },
ahash::{AHashMap, AHashSet}, ahash::{AHashMap, AHashSet},
bstr::{ByteSlice, ByteVec}, bstr::ByteSlice,
futures_util::{FutureExt, select}, futures_util::{FutureExt, select},
smallvec::SmallVec, smallvec::SmallVec,
std::{ std::{
@ -838,398 +837,6 @@ impl Wm {
} }
} }
fn compute_input_model(&self, data: &Rc<XwindowData>) {
let has_wm_take_focus = data.info.protocols.contains(&self.atoms.WM_TAKE_FOCUS);
let accepts_input = data.info.icccm_hints.input.get();
let model = match (accepts_input, has_wm_take_focus) {
(false, false) => XInputModel::None,
(true, false) => XInputModel::Passive,
(true, true) => XInputModel::Local,
(false, true) => XInputModel::Global,
};
data.info.input_model.set(model);
}
async fn load_window_wm_window_role(&self, data: &Rc<XwindowData>) {
let property_changed = || {
if let Some(window) = data.window.get() {
window.toplevel_data.property_changed(TL_CHANGED_ROLE);
}
};
let mut buf = vec![];
match self
.c
.get_property::<u8>(data.window_id, self.atoms.WM_WINDOW_ROLE, 0, &mut buf)
.await
{
Ok(ty) if ty == ATOM_STRING => {}
Ok(ty) if ty == self.atoms.UTF8_STRING => {}
Ok(ty) => {
self.unexpected_type(data.window_id, "WM_WINDOW_ROLE", ty)
.await;
return;
}
Err(XconError::PropertyUnavailable) => {
data.info.role.borrow_mut().take();
property_changed();
return;
}
Err(e) => {
log::error!(
"Could not retrieve WM_WINDOW_ROLE property: {}",
ErrorFmt(e)
);
return;
}
}
// log::info!("{} role {}", data.window_id, buf.as_bstr());
*data.info.role.borrow_mut() = Some(buf.into_string_lossy());
property_changed();
}
async fn load_window_wm_class(&self, data: &Rc<XwindowData>) {
let mut buf = vec![];
let property_changed = || {
if let Some(window) = data.window.get() {
let class = data.info.class.borrow();
for handle in window.toplevel_data.manager_handles.lock().values() {
handle.send_app_id(class.as_deref().unwrap_or_default());
handle.send_done();
}
window.toplevel_data.property_changed(TL_CHANGED_CLASS_INST);
}
};
match self
.c
.get_property::<u8>(data.window_id, ATOM_WM_CLASS, 0, &mut buf)
.await
{
Ok(ty) if ty == ATOM_STRING => {}
Ok(ty) if ty == self.atoms.UTF8_STRING => {}
Ok(ty) => {
self.unexpected_type(data.window_id, "WM_CLASS", ty).await;
return;
}
Err(XconError::PropertyUnavailable) => {
data.info.instance.borrow_mut().take();
data.info.class.borrow_mut().take();
property_changed();
return;
}
Err(e) => {
log::error!("Could not retrieve WM_CLASS property: {}", ErrorFmt(e));
return;
}
}
let mut iter = buf.split(|c| *c == 0);
let mut map = || Some(iter.next().unwrap_or(&[]).to_str_lossy().into_owned());
*data.info.instance.borrow_mut() = map();
*data.info.class.borrow_mut() = map();
property_changed();
}
async fn load_window_wm_name2(&self, data: &Rc<XwindowData>, prop: u32, name: &str) {
let mut buf = vec![];
match self
.c
.get_property::<u8>(data.window_id, prop, 0, &mut buf)
.await
{
Ok(ty) if ty == ATOM_STRING && data.info.utf8_title.get() => return,
Ok(ty) if ty == ATOM_STRING => {}
Ok(ty) if ty == self.atoms.COMPOUND_TEXT => return, // used by java.
Ok(ty) if ty == self.atoms.UTF8_STRING => {
data.info.utf8_title.set(true);
}
Ok(ty) => {
self.unexpected_type(data.window_id, name, ty).await;
return;
}
Err(XconError::PropertyUnavailable) => return,
Err(e) => {
log::error!("Could not retrieve {} property: {}", name, ErrorFmt(e));
return;
}
}
let title = buf.as_bstr().to_string();
if let Some(window) = data.window.get() {
window.toplevel_data.set_title(&title);
window.tl_title_changed();
}
*data.info.title.borrow_mut() = Some(title);
data.title_changed();
}
async fn unexpected_type(&self, window: u32, prop: &str, ty: u32) {
let mut ty_name = "unknown".as_bytes().as_bstr();
let res = self.c.call(&GetAtomName { atom: ty }).await;
if let Ok(res) = &res {
ty_name = res.get().name;
}
log::error!(
"Property {} of window {} has unexpected type {} ({})",
prop,
window,
ty_name,
ty
);
}
async fn load_window_wm_name(&self, data: &Rc<XwindowData>) {
self.load_window_wm_name2(data, ATOM_WM_NAME, "WM_NAME")
.await;
}
async fn load_window_net_wm_name(&self, data: &Rc<XwindowData>) {
self.load_window_wm_name2(data, self.atoms._NET_WM_NAME, "_NET_WM_NAME")
.await;
}
async fn load_window_wm_transient_for(&self, data: &Rc<XwindowData>) {
let mut buf = vec![];
if let Err(e) = self
.c
.get_property::<u32>(data.window_id, ATOM_WM_TRANSIENT_FOR, ATOM_WINDOW, &mut buf)
.await
{
if not_matches!(e, XconError::PropertyUnavailable) {
log::error!(
"Could not retrieve WM_TRANSIENT_FOR property: {}",
ErrorFmt(e)
);
}
}
if let Some(old) = data.parent.take() {
old.children.remove(&data.window_id);
}
if let Some(w) = buf.first()
&& let Some(w) = self.windows.get(w)
{
if data.is_ancestor_of(w.clone()) {
log::error!("Cannot set WM_TRANSIENT_FOR because it would create a cycle");
return;
}
w.children.set(data.window_id, data.clone());
data.parent.set(Some(w.clone()));
}
}
async fn load_window_wm_protocols(&self, data: &Rc<XwindowData>) {
let mut buf = vec![];
if let Err(e) = self
.c
.get_property::<u32>(data.window_id, self.atoms.WM_PROTOCOLS, ATOM_ATOM, &mut buf)
.await
{
if not_matches!(e, XconError::PropertyUnavailable) {
log::error!("Could not retrieve WM_PROTOCOLS property: {}", ErrorFmt(e));
}
return;
}
data.info.protocols.clear();
data.info
.protocols
.lock()
.extend(buf.iter().copied().map(|v| (v, ())));
self.compute_input_model(data);
}
async fn load_window_wm_hints(&self, data: &Rc<XwindowData>) {
let mut buf = vec![];
if let Err(e) = self
.c
.get_property::<u32>(data.window_id, self.atoms.WM_HINTS, 0, &mut buf)
.await
{
if not_matches!(e, XconError::PropertyUnavailable) {
log::error!("Could not retrieve WM_HINTS property: {}", ErrorFmt(e));
}
data.info.icccm_hints.input.set(true);
self.compute_input_model(data);
return;
}
let mut values = [0; 9];
let len = values.len().min(buf.len());
values[..len].copy_from_slice(&buf[..len]);
data.info.icccm_hints.flags.set(values[0] as i32);
data.info.icccm_hints.input.set(values[1] != 0);
data.info.icccm_hints.initial_state.set(values[2] as i32);
data.info.icccm_hints.icon_pixmap.set(values[3]);
data.info.icccm_hints.icon_window.set(values[4]);
data.info.icccm_hints.icon_x.set(values[5] as i32);
data.info.icccm_hints.icon_y.set(values[6] as i32);
data.info.icccm_hints.icon_mask.set(values[7]);
data.info.icccm_hints.window_group.set(values[8]);
if data
.info
.icccm_hints
.flags
.get()
.not_contains(ICCCM_WM_HINT_INPUT)
{
data.info.icccm_hints.input.set(true);
}
self.compute_input_model(data);
}
async fn load_window_wm_normal_hints(&self, data: &Rc<XwindowData>) {
let mut buf = vec![];
if let Err(e) = self
.c
.get_property::<u32>(
data.window_id,
self.atoms.WM_NORMAL_HINTS,
ATOM_WM_SIZE_HINTS,
&mut buf,
)
.await
{
if not_matches!(e, XconError::PropertyUnavailable) {
log::error!(
"Could not retrieve WM_NORMAL_HINTS property: {}",
ErrorFmt(e)
);
}
return;
}
let mut values = [0; 18];
let len = values.len().min(buf.len());
values[..len].copy_from_slice(&buf[..len]);
data.info.normal_hints.flags.set(values[0]);
data.info.normal_hints.x.set(values[1] as i32);
data.info.normal_hints.y.set(values[2] as i32);
data.info.normal_hints.width.set(values[3] as i32);
data.info.normal_hints.height.set(values[4] as i32);
data.info.normal_hints.min_width.set(values[5] as i32);
data.info.normal_hints.min_height.set(values[6] as i32);
data.info.normal_hints.max_width.set(values[7] as i32);
data.info.normal_hints.max_height.set(values[8] as i32);
data.info.normal_hints.width_inc.set(values[9] as i32);
data.info.normal_hints.height_inc.set(values[10] as i32);
data.info.normal_hints.min_aspect_num.set(values[11] as i32);
data.info.normal_hints.min_aspect_den.set(values[12] as i32);
data.info.normal_hints.max_aspect_num.set(values[13] as i32);
data.info.normal_hints.max_aspect_den.set(values[14] as i32);
data.info.normal_hints.base_width.set(values[15] as i32);
data.info.normal_hints.base_height.set(values[16] as i32);
data.info.normal_hints.win_gravity.set(values[17]);
self.update_wants_floating(data);
}
async fn load_window_motif_wm_hints(&self, data: &Rc<XwindowData>) {
let mut buf = vec![];
if let Err(e) = self
.c
.get_property::<u32>(data.window_id, self.atoms._MOTIF_WM_HINTS, 0, &mut buf)
.await
{
if not_matches!(e, XconError::PropertyUnavailable) {
log::error!(
"Could not retrieve _MOTIF_WM_HINTS property: {}",
ErrorFmt(e)
);
}
return;
}
let mut values = [0; 5];
let len = values.len().min(buf.len());
values[..len].copy_from_slice(&buf[..len]);
data.info
.motif_hints
.flags
.set(values[MWM_HINTS_FLAGS_FIELD]);
data.info
.motif_hints
.decorations
.set(values[MWM_HINTS_DECORATIONS_FIELD]);
}
async fn load_window_net_startup_id(&self, data: &Rc<XwindowData>) {
let mut buf = vec![];
match self
.c
.get_property::<u8>(data.window_id, self.atoms._NET_STARTUP_ID, 0, &mut buf)
.await
{
Ok(ty) if ty == ATOM_STRING => {}
Ok(ty) if ty == self.atoms.UTF8_STRING => {}
Ok(ty) => {
self.unexpected_type(data.window_id, "_NET_STARTUP_ID", ty)
.await;
return;
}
Err(XconError::PropertyUnavailable) => return,
Err(e) => {
log::error!(
"Could not retrieve _NET_STARTUP_ID property: {}",
ErrorFmt(e)
);
return;
}
}
*data.info.startup_id.borrow_mut() = Some(buf.into());
}
async fn load_window_net_wm_state(&self, data: &Rc<XwindowData>) {
data.info.fullscreen.set(false);
let mut buf = vec![];
if let Err(e) = self
.c
.get_property::<u32>(data.window_id, self.atoms._NET_WM_STATE, 0, &mut buf)
.await
{
if not_matches!(e, XconError::PropertyUnavailable) {
log::error!("Could not retrieve _NET_WM_STATE property: {}", ErrorFmt(e));
}
return;
}
for prop in buf {
if prop == self.atoms._NET_WM_STATE_MODAL {
data.info.modal.set(true);
self.update_wants_floating(data);
} else if prop == self.atoms._NET_WM_STATE_FULLSCREEN {
data.info.fullscreen.set(true);
} else if prop == self.atoms._NET_WM_STATE_MAXIMIZED_VERT {
data.info.maximized_vert.set(true);
} else if prop == self.atoms._NET_WM_STATE_MAXIMIZED_HORZ {
data.info.maximized_horz.set(true);
} else if prop == self.atoms._NET_WM_STATE_HIDDEN {
data.info.minimized.set(true);
}
}
}
async fn load_window_net_wm_window_type(&self, data: &Rc<XwindowData>) {
let mut buf = vec![];
if let Err(e) = self
.c
.get_property::<u32>(
data.window_id,
self.atoms._NET_WM_WINDOW_TYPE,
ATOM_ATOM,
&mut buf,
)
.await
{
if not_matches!(e, XconError::PropertyUnavailable) {
log::error!(
"Could not retrieve _NET_WM_WINDOW_TYPE property: {}",
ErrorFmt(e)
);
}
return;
}
data.info
.never_focus
.set(buf.iter().any(|t| self.never_focus.contains(t)));
data.info.window_types.clear();
data.info
.window_types
.lock()
.extend(buf.iter().copied().map(|v| (v, ())));
self.update_wants_floating(data);
}
async fn create_window(&mut self, data: &Rc<XwindowData>, surface: Rc<WlSurface>) { async fn create_window(&mut self, data: &Rc<XwindowData>, surface: Rc<WlSurface>) {
if data.window.is_some() { if data.window.is_some() {
log::error!("The xwindow has already been constructed"); log::error!("The xwindow has already been constructed");

View file

@ -0,0 +1,413 @@
use {
super::Wm,
crate::{
criteria::tlm::{TL_CHANGED_CLASS_INST, TL_CHANGED_ROLE},
ifs::wl_surface::x_surface::xwindow::{XInputModel, XwindowData},
tree::ToplevelNode,
utils::{bitflags::BitflagsExt, errorfmt::ErrorFmt},
wire_xcon::GetAtomName,
xcon::{
XconError,
consts::{
ATOM_ATOM, ATOM_STRING, ATOM_WINDOW, ATOM_WM_CLASS, ATOM_WM_NAME,
ATOM_WM_SIZE_HINTS, ATOM_WM_TRANSIENT_FOR, ICCCM_WM_HINT_INPUT,
MWM_HINTS_DECORATIONS_FIELD, MWM_HINTS_FLAGS_FIELD,
},
},
},
bstr::{ByteSlice, ByteVec},
std::rc::Rc,
};
impl Wm {
pub(super) fn compute_input_model(&self, data: &Rc<XwindowData>) {
let has_wm_take_focus = data.info.protocols.contains(&self.atoms.WM_TAKE_FOCUS);
let accepts_input = data.info.icccm_hints.input.get();
let model = match (accepts_input, has_wm_take_focus) {
(false, false) => XInputModel::None,
(true, false) => XInputModel::Passive,
(true, true) => XInputModel::Local,
(false, true) => XInputModel::Global,
};
data.info.input_model.set(model);
}
pub(super) async fn load_window_wm_window_role(&self, data: &Rc<XwindowData>) {
let property_changed = || {
if let Some(window) = data.window.get() {
window.toplevel_data.property_changed(TL_CHANGED_ROLE);
}
};
let mut buf = vec![];
match self
.c
.get_property::<u8>(data.window_id, self.atoms.WM_WINDOW_ROLE, 0, &mut buf)
.await
{
Ok(ty) if ty == ATOM_STRING => {}
Ok(ty) if ty == self.atoms.UTF8_STRING => {}
Ok(ty) => {
self.unexpected_type(data.window_id, "WM_WINDOW_ROLE", ty)
.await;
return;
}
Err(XconError::PropertyUnavailable) => {
data.info.role.borrow_mut().take();
property_changed();
return;
}
Err(e) => {
log::error!(
"Could not retrieve WM_WINDOW_ROLE property: {}",
ErrorFmt(e)
);
return;
}
}
*data.info.role.borrow_mut() = Some(buf.into_string_lossy());
property_changed();
}
pub(super) async fn load_window_wm_class(&self, data: &Rc<XwindowData>) {
let mut buf = vec![];
let property_changed = || {
if let Some(window) = data.window.get() {
let class = data.info.class.borrow();
for handle in window.toplevel_data.manager_handles.lock().values() {
handle.send_app_id(class.as_deref().unwrap_or_default());
handle.send_done();
}
window.toplevel_data.property_changed(TL_CHANGED_CLASS_INST);
}
};
match self
.c
.get_property::<u8>(data.window_id, ATOM_WM_CLASS, 0, &mut buf)
.await
{
Ok(ty) if ty == ATOM_STRING => {}
Ok(ty) if ty == self.atoms.UTF8_STRING => {}
Ok(ty) => {
self.unexpected_type(data.window_id, "WM_CLASS", ty).await;
return;
}
Err(XconError::PropertyUnavailable) => {
data.info.instance.borrow_mut().take();
data.info.class.borrow_mut().take();
property_changed();
return;
}
Err(e) => {
log::error!("Could not retrieve WM_CLASS property: {}", ErrorFmt(e));
return;
}
}
let mut iter = buf.split(|c| *c == 0);
let mut map = || Some(iter.next().unwrap_or(&[]).to_str_lossy().into_owned());
*data.info.instance.borrow_mut() = map();
*data.info.class.borrow_mut() = map();
property_changed();
}
async fn load_window_wm_name2(&self, data: &Rc<XwindowData>, prop: u32, name: &str) {
let mut buf = vec![];
match self
.c
.get_property::<u8>(data.window_id, prop, 0, &mut buf)
.await
{
Ok(ty) if ty == ATOM_STRING && data.info.utf8_title.get() => return,
Ok(ty) if ty == ATOM_STRING => {}
Ok(ty) if ty == self.atoms.COMPOUND_TEXT => return,
Ok(ty) if ty == self.atoms.UTF8_STRING => {
data.info.utf8_title.set(true);
}
Ok(ty) => {
self.unexpected_type(data.window_id, name, ty).await;
return;
}
Err(XconError::PropertyUnavailable) => return,
Err(e) => {
log::error!("Could not retrieve {} property: {}", name, ErrorFmt(e));
return;
}
}
let title = buf.as_bstr().to_string();
if let Some(window) = data.window.get() {
window.toplevel_data.set_title(&title);
window.tl_title_changed();
}
*data.info.title.borrow_mut() = Some(title);
data.title_changed();
}
async fn unexpected_type(&self, window: u32, prop: &str, ty: u32) {
let mut ty_name = "unknown".as_bytes().as_bstr();
let res = self.c.call(&GetAtomName { atom: ty }).await;
if let Ok(res) = &res {
ty_name = res.get().name;
}
log::error!(
"Property {} of window {} has unexpected type {} ({})",
prop,
window,
ty_name,
ty
);
}
pub(super) async fn load_window_wm_name(&self, data: &Rc<XwindowData>) {
self.load_window_wm_name2(data, ATOM_WM_NAME, "WM_NAME")
.await;
}
pub(super) async fn load_window_net_wm_name(&self, data: &Rc<XwindowData>) {
self.load_window_wm_name2(data, self.atoms._NET_WM_NAME, "_NET_WM_NAME")
.await;
}
pub(super) async fn load_window_wm_transient_for(&self, data: &Rc<XwindowData>) {
let mut buf = vec![];
if let Err(e) = self
.c
.get_property::<u32>(data.window_id, ATOM_WM_TRANSIENT_FOR, ATOM_WINDOW, &mut buf)
.await
{
if not_matches!(e, XconError::PropertyUnavailable) {
log::error!(
"Could not retrieve WM_TRANSIENT_FOR property: {}",
ErrorFmt(e)
);
}
}
if let Some(old) = data.parent.take() {
old.children.remove(&data.window_id);
}
if let Some(w) = buf.first()
&& let Some(w) = self.windows.get(w)
{
if data.is_ancestor_of(w.clone()) {
log::error!("Cannot set WM_TRANSIENT_FOR because it would create a cycle");
return;
}
w.children.set(data.window_id, data.clone());
data.parent.set(Some(w.clone()));
}
}
pub(super) async fn load_window_wm_protocols(&self, data: &Rc<XwindowData>) {
let mut buf = vec![];
if let Err(e) = self
.c
.get_property::<u32>(data.window_id, self.atoms.WM_PROTOCOLS, ATOM_ATOM, &mut buf)
.await
{
if not_matches!(e, XconError::PropertyUnavailable) {
log::error!("Could not retrieve WM_PROTOCOLS property: {}", ErrorFmt(e));
}
return;
}
data.info.protocols.clear();
data.info
.protocols
.lock()
.extend(buf.iter().copied().map(|v| (v, ())));
self.compute_input_model(data);
}
pub(super) async fn load_window_wm_hints(&self, data: &Rc<XwindowData>) {
let mut buf = vec![];
if let Err(e) = self
.c
.get_property::<u32>(data.window_id, self.atoms.WM_HINTS, 0, &mut buf)
.await
{
if not_matches!(e, XconError::PropertyUnavailable) {
log::error!("Could not retrieve WM_HINTS property: {}", ErrorFmt(e));
}
data.info.icccm_hints.input.set(true);
self.compute_input_model(data);
return;
}
let mut values = [0; 9];
let len = values.len().min(buf.len());
values[..len].copy_from_slice(&buf[..len]);
data.info.icccm_hints.flags.set(values[0] as i32);
data.info.icccm_hints.input.set(values[1] != 0);
data.info.icccm_hints.initial_state.set(values[2] as i32);
data.info.icccm_hints.icon_pixmap.set(values[3]);
data.info.icccm_hints.icon_window.set(values[4]);
data.info.icccm_hints.icon_x.set(values[5] as i32);
data.info.icccm_hints.icon_y.set(values[6] as i32);
data.info.icccm_hints.icon_mask.set(values[7]);
data.info.icccm_hints.window_group.set(values[8]);
if data
.info
.icccm_hints
.flags
.get()
.not_contains(ICCCM_WM_HINT_INPUT)
{
data.info.icccm_hints.input.set(true);
}
self.compute_input_model(data);
}
pub(super) async fn load_window_wm_normal_hints(&self, data: &Rc<XwindowData>) {
let mut buf = vec![];
if let Err(e) = self
.c
.get_property::<u32>(
data.window_id,
self.atoms.WM_NORMAL_HINTS,
ATOM_WM_SIZE_HINTS,
&mut buf,
)
.await
{
if not_matches!(e, XconError::PropertyUnavailable) {
log::error!(
"Could not retrieve WM_NORMAL_HINTS property: {}",
ErrorFmt(e)
);
}
return;
}
let mut values = [0; 18];
let len = values.len().min(buf.len());
values[..len].copy_from_slice(&buf[..len]);
data.info.normal_hints.flags.set(values[0]);
data.info.normal_hints.x.set(values[1] as i32);
data.info.normal_hints.y.set(values[2] as i32);
data.info.normal_hints.width.set(values[3] as i32);
data.info.normal_hints.height.set(values[4] as i32);
data.info.normal_hints.min_width.set(values[5] as i32);
data.info.normal_hints.min_height.set(values[6] as i32);
data.info.normal_hints.max_width.set(values[7] as i32);
data.info.normal_hints.max_height.set(values[8] as i32);
data.info.normal_hints.width_inc.set(values[9] as i32);
data.info.normal_hints.height_inc.set(values[10] as i32);
data.info.normal_hints.min_aspect_num.set(values[11] as i32);
data.info.normal_hints.min_aspect_den.set(values[12] as i32);
data.info.normal_hints.max_aspect_num.set(values[13] as i32);
data.info.normal_hints.max_aspect_den.set(values[14] as i32);
data.info.normal_hints.base_width.set(values[15] as i32);
data.info.normal_hints.base_height.set(values[16] as i32);
data.info.normal_hints.win_gravity.set(values[17]);
self.update_wants_floating(data);
}
pub(super) async fn load_window_motif_wm_hints(&self, data: &Rc<XwindowData>) {
let mut buf = vec![];
if let Err(e) = self
.c
.get_property::<u32>(data.window_id, self.atoms._MOTIF_WM_HINTS, 0, &mut buf)
.await
{
if not_matches!(e, XconError::PropertyUnavailable) {
log::error!(
"Could not retrieve _MOTIF_WM_HINTS property: {}",
ErrorFmt(e)
);
}
return;
}
let mut values = [0; 5];
let len = values.len().min(buf.len());
values[..len].copy_from_slice(&buf[..len]);
data.info
.motif_hints
.flags
.set(values[MWM_HINTS_FLAGS_FIELD]);
data.info
.motif_hints
.decorations
.set(values[MWM_HINTS_DECORATIONS_FIELD]);
}
pub(super) async fn load_window_net_startup_id(&self, data: &Rc<XwindowData>) {
let mut buf = vec![];
match self
.c
.get_property::<u8>(data.window_id, self.atoms._NET_STARTUP_ID, 0, &mut buf)
.await
{
Ok(ty) if ty == ATOM_STRING => {}
Ok(ty) if ty == self.atoms.UTF8_STRING => {}
Ok(ty) => {
self.unexpected_type(data.window_id, "_NET_STARTUP_ID", ty)
.await;
return;
}
Err(XconError::PropertyUnavailable) => return,
Err(e) => {
log::error!(
"Could not retrieve _NET_STARTUP_ID property: {}",
ErrorFmt(e)
);
return;
}
}
*data.info.startup_id.borrow_mut() = Some(buf.into());
}
pub(super) async fn load_window_net_wm_state(&self, data: &Rc<XwindowData>) {
data.info.fullscreen.set(false);
let mut buf = vec![];
if let Err(e) = self
.c
.get_property::<u32>(data.window_id, self.atoms._NET_WM_STATE, 0, &mut buf)
.await
{
if not_matches!(e, XconError::PropertyUnavailable) {
log::error!("Could not retrieve _NET_WM_STATE property: {}", ErrorFmt(e));
}
return;
}
for prop in buf {
if prop == self.atoms._NET_WM_STATE_MODAL {
data.info.modal.set(true);
self.update_wants_floating(data);
} else if prop == self.atoms._NET_WM_STATE_FULLSCREEN {
data.info.fullscreen.set(true);
} else if prop == self.atoms._NET_WM_STATE_MAXIMIZED_VERT {
data.info.maximized_vert.set(true);
} else if prop == self.atoms._NET_WM_STATE_MAXIMIZED_HORZ {
data.info.maximized_horz.set(true);
} else if prop == self.atoms._NET_WM_STATE_HIDDEN {
data.info.minimized.set(true);
}
}
}
pub(super) async fn load_window_net_wm_window_type(&self, data: &Rc<XwindowData>) {
let mut buf = vec![];
if let Err(e) = self
.c
.get_property::<u32>(
data.window_id,
self.atoms._NET_WM_WINDOW_TYPE,
ATOM_ATOM,
&mut buf,
)
.await
{
if not_matches!(e, XconError::PropertyUnavailable) {
log::error!(
"Could not retrieve _NET_WM_WINDOW_TYPE property: {}",
ErrorFmt(e)
);
}
return;
}
data.info
.never_focus
.set(buf.iter().any(|t| self.never_focus.contains(t)));
data.info.window_types.clear();
data.info
.window_types
.lock()
.extend(buf.iter().copied().map(|v| (v, ())));
self.update_wants_floating(data);
}
}

View file

@ -1,4 +1,8 @@
use {super::*, super::transfer::{WaylandToXTransfer, XToWaylandTransfer}}; use {
super::*,
super::transfer::{WaylandToXTransfer, XToWaylandTransfer},
crate::wire_xcon::GetAtomName,
};
pub(super) struct EnhancedOffer { pub(super) struct EnhancedOffer {
offer: Rc<XDataOffer>, offer: Rc<XDataOffer>,